ES6中变量解构赋值

数组的解构赋值

ES6规定以一定模式从数组、对象中提取值,然后给变量赋值叫做解构。

本质上就是一种匹配模式,等号两边模式相同,左边的变量就能对应的值。

假如解构不成功会赋值为undefined。

不需要匹配的位置可以置空

js 复制代码
let [ a, b, c] = [1, 2, 3];
// a = 1
// b = 2
// c = 3

let [, , d] = [1, 2, 3];
// d = 3

1. 不完全解构

指的是左侧只能匹配右侧一部分模式,这种情况叫做不完全解构。

js 复制代码
let [x, y] = [1, 2, 3];
// x = 1; y = 2

2. 等号右侧不是数组

如果等于右侧不是数组会报错

js 复制代码
let [foo] = 1; // 报错
let [foo] = true; // 报错

在执行时会先转化,其实只要数据结构具有Iterator接口,都能解构。

3. 嵌套解构

4. 默认值

解构时可以设置一个默认值,假如解构不成功时可以使用默认值,否则会报错。

只有解构时值为undefined,才会使用默认值。

js 复制代码
let [ x = 1] = [];
// x = 1

这里结构变量x时,不存在但是给定默认值为1。

js 复制代码
let [x, y = 1] = ['a'];
// x = 'a' y = 1

let [x = 1] = [undefined];
// x = 1

let [x = 1] = [null];
// x = 1

默认值也可以是表达式、其他变量

如果是表达式,只有使用时才会进行计算求值,否则不会主动计算。

js 复制代码
function foo() {
    return 2;   
}
let [x = foo()] = [1]; // 1
let [x = foo()] = [undefined]; // 2

第一个解构时不会执行foo函数,因为解构能成功,第二个解构的值为undefined,所以会执行foo函数。

对于其他变量,必须保证变量是已经存在的。

js 复制代码
let [x = 1, y = x] = []; // x = 1; y = 1
let [x = 1, y = x] = [2]; // x = 2; y = 2
let [x = 1, y = x] = [2, 3]; // x = 2; y = 3
let [x = y, y = 1] = []; // 报错

最后一个会报错是因为,y还没有声明呢,就直接使用了。

对象的解构赋值

对象的解构不必像数组那样按顺序排列,只要变量与属性名一致就能获取到值,对于取不到值的会被赋值为undefined。

js 复制代码
let { foo, bar } = { foo: 'a', bar: 'b'};
// foo = 'a'; bar = 'b'

let { baz } =  { foo: 'a', bar: 'b'};
// baz = undefined 不存在

对于属性名不一致可以使用冒号连接,冒号左边表示匹配的模式,这个模式要与解构的对象的属性名一致,冒号有侧就是自定义的变量名。

对象的解构本质就是通过冒号,左侧进行查找,右侧被真正赋值,只不过平时左侧、右侧名称一致,简写了而已。

js 复制代码
let { foo: baz } = { foo: 'a', bar: 'b'};
// baz = 'a'

1. 嵌套解构

js 复制代码
let obj = {
    p: ['hello', { 
        y: 'world'
    }]
}
let { p: [x, {y}]} = obj;
// x = 'hello'
// y = 'world'

这里的p是匹配模式,并不是变量

2. 默认值

只有对象的属性值为undefined时,默认值才能生效。

js 复制代码
let { x = 3 } = {};
// x = 3

对象的解构赋值可以很方便地将现有对象的方法赋值给某个变量。

js 复制代码
let { log, sin, cos } = Math; 

数组是特殊的对象,可以对数组进行对象属性结构,以数组的index。

js 复制代码
let arr = [1, 2, 3];
let { 0: first, [arr.length - 1 ]:last } = arr;
// first = 1; last = 3

字符串的解构赋值

字符串也能解构,也解构成一个类似数组的对象。

不需要匹配的位置可以置空

js 复制代码
let [a, b] = 'world';
// a = 'w'; b = 'o'

let [a, , b] = 'world';
// a = 'w'; b = 'r'

类似数组的对象都有一个length属性,所以可以对length属性进行解构

js 复制代码
let { length: len } = 'hello';
// len = 5

数值和布尔类型解构

解构赋值时,等号右侧只要不是对象或者数组,就会先转为对象

js 复制代码
let { toString: s } = 123;
s === Number.prototype.toString // true

函数参数的解构

函数的参数也能进行解构,也能使用默认值。

js 复制代码
function add ({x, y}) {
    return x + y;
}
add(1, 2); // 3

function boo({x = 1, y = 2}) {
    return x + y;
}
add()

括号问题

正常解构是声明变量并且赋值,假如说变量已经声明成功,直接赋值,这时需要有所注意。

解构赋值虽然很方便,但是解析起来不容易。对于编译器来说,一个式子到底是模式还是表达式,没有办法从一开始就知道,必须解析到(或者解析不到)等号才知道,所以ES6规定,为了不导致歧义,不要使用圆括号。

js 复制代码
let x;
{x} = {x:1};
// 报错

因为js会把{x}当做一个代码块,而不是变量,从而发生语法错误。

1. 不能使用圆括号的情况

  • 变量声明语句

会导致全部报错

js 复制代码
let [ (a) ] = [1];
let { x: (c) } = {};
let ({ x: c }) = {};
let { (x: c) } = {};
let { (x): c } = {};

let { o: ({ p:p }) } = { o: { p: 2 } };
  • 函数参数

函数的参数属于变量声明,不能使用圆括号

js 复制代码
function f([(z)]) {
    return z;
}
  • 赋值语句的模式
js 复制代码
({ p:a }) = { p: 42 };
([a]) = [5];
[({ p: a }), {x: c }] = [{}, {}];

不管是一部分模式还是全部模式都放在括号里面,都会报错。

2. 可以使用圆括号

赋值语句的非模式部分可以使用圆括号

js 复制代码
[(b)] = [3];
({ p: (d) } = {});
[(parseInt.prop)] = [3];

用途

交换变量的值

js 复制代码
let x = 1;
let y = 2;
[x, y] = [y, x];
// x = 2; y = 1

从函数返回多个值

函数只能返回一个值,如果真要返回多个只能放在数组和对象中,但是使用解构赋值就很方便。

js 复制代码
function example() {
    return [1, 2, 3];
}
let [a, b, c] = example();

函数参数的定义

解构赋值可以方便地将一组参数与变量名对应起来。

js 复制代码
// 参数是一组有次序的值
function f([x, y, z]) {}
f([1, 2, 3]);
js 复制代码
// 参数是一组无次序的值
function f([x, y, z]) {}
f([z: 1, y: 2, x: 3]);

提取JSON数据

函数参数的默认值

在之前函数要是有默认值时,需要加判断,很不方便。

之前的

js 复制代码
function foo(x) {
    var y;
    if(x != undefined) {
        y = '默认值';
    }
    y = x;
}
foo();

现在直接使用解构赋值,添加默认值就可以

js 复制代码
function foo(x = '默认值') {
    
}
foo();

变量Map解构

任何部署了Iterator接口的对象都可以使用for...of循环遍历,Map结构原生支持Iterator接口,因此配合变量的解构赋值获取键名和键值很方便。

js 复制代码
var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
    console.log(`${key} is ${value}`);
}
// first is helllo
// second is world

获取键名

js 复制代码
for(let [key] of map) {
    // ...
}

获取键值

js 复制代码
for (let [, value] of map) {
    // ...
}

输入模块的指定方法

加载模块时,汪汪需要指定输入的方法,则使用解构赋值使输入语句清晰

js 复制代码
// 现在
const { SourceMapConsumer, SourceNode } = require('source-map');

// 之前
const sourceMap = require('source-map');
const SourceMapConsumer = sourceMap.SourceMapConsumer();
const SourceNode = sourceMap.SourceNode();
相关推荐
昨天;明天。今天。1 小时前
案例-表白墙简单实现
前端·javascript·css
数云界1 小时前
如何在 DAX 中计算多个周期的移动平均线
java·服务器·前端
风清扬_jd1 小时前
Chromium 如何定义一个chrome.settingsPrivate接口给前端调用c++
前端·c++·chrome
安冬的码畜日常1 小时前
【玩转 JS 函数式编程_006】2.2 小试牛刀:用函数式编程(FP)实现事件只触发一次
开发语言·前端·javascript·函数式编程·tdd·fp·jasmine
ChinaDragonDreamer1 小时前
Vite:为什么选 Vite
前端
小御姐@stella1 小时前
Vue 之组件插槽Slot用法(组件间通信一种方式)
前端·javascript·vue.js
GISer_Jing1 小时前
【React】增量传输与渲染
前端·javascript·面试
GISer_Jing1 小时前
WebGL在低配置电脑的应用
javascript
eHackyd1 小时前
前端知识汇总(持续更新)
前端
万叶学编程5 小时前
Day02-JavaScript-Vue
前端·javascript·vue.js