变量的解构赋值
ECMAScript 6 允许按照一定模式从数组或对象中提取值,对变量进行赋值。这种赋值方式被称为“解构赋值”(Destructuring)。
-
ECMAScript 5 为变量赋值方式如下:
var a = 10; var b = 11; var c = 12;
-
ECMAScript 6 为变量赋值方式如下:
let [a, b, c] = [10, 11, 12];
ECMAScript 6 的“解构赋值”本质上属于“模式匹配”。赋值运算符两边的模式相同,左边的变量会被赋予对应位置的值。
理解
解构赋值指定的数组或对象中提取值,为指定变量进行赋值
-
语法结构:
var/let [变量名称1, 变量名称2, ...] = 数组或对象
-
注意:变量索引值对应值的索引值
解构赋值失败
如果解构赋值失败的话,变量的值等于 undefined
。
let [a] = [];
console.log(a); // undefined
let [m, n] = [1]
console.log(m, n); // 1 undefined
解构赋值失败就是变量没初始化
不想解构赋值失败的话, 定义变量的数量与值的数量保持一致
下面代码不是解构赋值失败
let [a, b]=[1,undefined]
console.log(a, b); // 1 undefined
理解
定义变量的数量大于值的数量
不完全解构赋值
如果赋值运算符左边的变量的模式只匹配赋值运算符右边数组的一部分的话,则会解构赋值不完全。
但这种情况下,解构赋值依旧可以成功。
let [a, b] = [1, 2, 3]
console.log(a, b); // 1 2
理解
定义变量的数量小于值的数量
默认值
默认值指的就是在解构赋值失败时,重写 undefined
默认值
let [x, y = 100] = [10];
console.log(x, y); // 10 100
值得注意的是,ECMAScript 6 内部使用全等于运算符判断指定位置是否存在值。所以只有当数组中成员的值等于 undefined
时,默认值才会生效。
理解
ES6,底层将,为变量赋值的值与 undefined
进行比较(全等于),指定的默认值生效
和函数的形参默认的默认值一样
对象的解构赋值
对象的解构赋值是通过变量名称与对象的属性名称一一对应实现的。
let {x, y} = {
x: 10,
y: 20
}
console.log(x, y); // 10 20
如果不对应,会导致解构赋值失败
let {a, b} = {
x: 10,
y: 20
}
console.log(a, b); // undefined undefined
赋值运算符两边格式不一致,会报错
let [m, n] = { // TypeError: {(intermediate value)(intermediate value)} is not iterable
}
console.log(m, n);
对象的解构赋值的情况
// 解构赋值失败
let {m, n} ={
m: 100
}
console.log(m, n); // 100 undefined
// 不完全解构赋值
let {x} = {
x: 100,
y: 1000
}
console.log(x); // 100
// 默认值
let {v, w=1} ={
v: 100,
w: undefined
}
console.log(v, w); // 100 1
扩展
解构赋值的值可是任何类型
let {m, n} = {
m: {
name: ' 张无忌'
},
n: function () {
return 10;
}
}
console.log(m, n) // {name: '张无忌'} [Function]
let [m, n] = [{name: '张无忌'}, function () {
return 10;
}]
console.log(n); // {name: '张无忌'} [Function]
赋值扩展
解构赋值:定义变量的结构与数组或对象的结构保持一致
- 数组的解构赋值:变量的索引值 与值的索引值保持一致
- 对象的解构赋值:变量的名称与对象属性的名称保持一致
let [[a, b], c] = [[1, 2], 3]
console.log(a, b, c); // 1 2 3
let {{name, age}, n} = { // SyntaxError: Unexpected token '{'
m: {
name: '张无忌',
age: 18
},
n: 10
}
console.log(name, age);
let {m: {name, age}, n} = {
m: {
name: '张无忌',
age: 18
},
n: 10
}
console.log(name, age); // 张无忌 18
字符串的解构赋值
字符串的解构赋值被转换成了类似于数组的对象。
变量的数量与字符串中字符的数量进行对应
let [a, b, c] = 'xyz';
console.log(a, b, c); // x y z
let [a, b, c] = 'xxyyzz';
console.log(a, b, c); // x x
y
将中文汉字作为一个字符来看待
let [a, b, c] = '大前端';
console.log(a, b, c); // 大 前 端
数值与布尔值的解构赋值
解构赋值时,如果赋值运算符右边是数值或布尔值的话,则会先转换为对象。
let {toString: m} = 100;
console.log(m === Number.prototype.toString); // true
解构赋值的规则是,只要赋值运算符右边的值不是对象或数组的话,会先转换为对象。由于 undefined
和 null
无法转换为对象,所以解构赋值时会报错。
let {toString: x} = true
console.log(x === Boolean.prototype.toString); // tru
函数参数的解构赋值
-
函数定义 - 形参 相当于在函数作用域中定义了一个局部变量(没有赋值)
-
函数调用 - 实参,相当于在函数作用域中为定义的变量进行赋值
function f ([a, b]) {
console.log(a, b);
}
f([10, 20]); // 10 20
function f({m, n}) {
console.log(m, n);
}
f({
m: 10,
n: 20
}); // 10 20
小括号问题
使用解构赋值虽然很方便,但是解析并不容易。对于解析器来讲,语句中到底是模式还是表达式,没有办法从开始就知道,必须解析到赋值运算符时才能知晓。
ECMAScript 6 的规则是只要有可能导致解构赋值的歧义,就不得使用小括号。
但是,这条规则实际上不那么容易分辨,处理起来相当麻烦。因此,建议只要有可能就不要再模式中使用小括号。
不能使用小括号的情况
以下三种解构赋值时不得使用小括号:
-
变量声明语句
// 全部报错 let [(a)] = [1]; let {x: (c)} = {}; let ({x: c}) = {}; let {(x: c)} = {}; let {(x): c} = {}; let { o: ({ p: p }) } = { o: { p: 2 } };
-
函数参数:函数参数也属于变量声明,因此不能带有小括号
// 报错 function f([(z)]) { return z; } // 报错 function f([z,(x)]) { return x; }
-
赋值语句的模式
// 全部报错 ({ p: a }) = { p: 42 }; ([a]) = [5];
解构赋值的用途
交换变量的值
解构赋值可用于两个变量之间交换值。
ES5:
let x = 1, y = 2;
let w = x;
x = y;
y = w;
console.log(x, y); // 2 1
ES6:
let x = 1, y = 2;
[x, y] = [y, x];
console.log(x, y); // 2 1
从函数返回多个值
函数一般只能返回一个值。如果想要返回多个值,只能将多个值放置在数组或对象中。如果使用解构赋值的话,很容易实现函数返回多个值。
ES5:
function fn() {
return [1, 2, 3];
// return {a: 1, b: 2, c: 3};
}
let arr = fn();
console.log(arr); // { a: 1, b: 2, c: 3 }
ES6:
function fn() {
return [1, 2, 3];
// return {a: 1, b: 2, c: 3};
}
let [a, b, c] = fn();
console.log(a, b, c); // 1 2 3
函数参数的定义
解构赋值可以很方便地将一组参 数与变量名对应起来。
function f([a, b, c = 0]) {
console.log(a, b, c);
}
f([1, 2]); // 1 2 0
提取 JSON 数据
解构赋值对于提取 JSON 对象中的数据内容尤其有用。
let jsonData = {
name: "张无忌",
age: 11,
job: "教主"
};
let { name, age, job } = jsonData;
console.log(name, age, job); // 张无忌 11 教主