变量的解构赋值
解构:es6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为结构。
1.数组的解构赋值``
1)在es5中,为变量赋值:
let a = 1
let b = 2
let c = 3
在es6中,可以写成这样:
let [a,b,c] = [1,2,3]
模式匹配!等号左边和右边的结构完全一致时,按照先后顺序一一匹配
let [foo,[[bar],baz]] = [1,[[2],3]];
foo //1
bar //2
baz //3
let[ , ,third] = ["foo","bar","baz"];
third //baz
let [x, ,y] = [1,2,3];
x //1
y //3
let [head,...tail] = [1,2,3,4];
head //1
tail //[2,3,4]
let[x,y,...z] = ['a'];
x // 'a'
y //undefined
z //[]
不完全解构
let [x, y] = [1, 2, 3];
x // 1
y // 2
let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
注意:如果等号右边不是数组或者严格上去讲如果等号右边不是可遍历的结构,那么也会报错
let [foo] = 1
let [foo] = false
let [foo] = NaN
let [foo] = undefined
let [foo] = null
let [foo] = {};
上面语句会报错,因为等号右边的值,要么转为对象以后不具备Iterator接口(前五个表达式),要么本身就不具备Iterator接口(最后一个表达式)
2)对于Set结构,也可以使用数组的结构赋值
let [x,y,z] = new Set(['a','b','c']);
x //"a"
3)默认值
1.注意,ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效。
let [foo = true] = []
foo //true
let [x,y = 'b'] = ['a'];
x = 'a' y = 'b'
let [x,y='b'] = ['a',undefined];
x = 'a' y = 'b'
let [x='b',y]=[null,'bill']
x = null y=bill
另外要注意,只有undefined的时候才会取默认值,null的时候不会
2.默认值可以是一个函数,但是只有当能取到默认值的时候,才会去执行该函数。
let [x=f()] = [1];
console.log(x)
//x = 1
3.默认值可以引用解构赋值的其他变量,但该变量必须已经声明。
let [x = 1, y = x] = []; // x=1; y=1
let [x = 1, y = x] = [2]; // 2wx=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = []; // ReferenceError: y is not defined
2.对象的解构赋值
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定,而对象的属性是没有次序的,变量必须与属性同名,才能取到正确的值
let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"
上方的例子中对象的属性名与变量名一致
let { bar, foo } = { foo: 'aaa', bar: 'bbb' }; 不简略写的话其实是:
let {bar:bar,foo:foo} = { foo: 'aaa', bar: 'bbb' }; 测试打印时所打印的foo其实是属性名后的变量,并不是属性名!
注意:对象的解构步骤是先找到同名属性,再进行匹配赋值。
例一:
let {foo:vkk} = {foo:"aaa",vkk:"bbb"}
在该对象解构中,首先匹配同名属性名,之后在同名属性中进行赋值,所以vkk = "aaa"。
例二:
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"
在该例子中对象解构,前面的p:[x,{y}]中的p是属性名,也叫模式,:后面的x,y叫变量。对象解构,先进行模式匹配,后对变量进行匹配赋值。所以x为hello y为world
例三:
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p, p: [x, { y }] } = obj;
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]
在该例子中,let { p, p: [x, { y }] }中的第一个p 是属于属性名与变量同步的情况,所以模式匹配后变量p被赋值为["Hello", {y: "World"}] 第二个p 同例二
例四:
const node = {
loc:{
start:{
line:1,
column:5
}
}
}
let {loc,loc:{start},loc:{start:{line}}} = node
console.log(loc)
console.log(start)
console.log(line)
输出结果:
{ start: { line: 1, column: 5 } }
{ line: 1, column: 5 }
1
该例子需要注意的是,在最后loc:{start:{line}}中,loc start都是模式 最后一个冒号后才是变量
对象解构的默认值:
默认值生效的条件是,对象的属性值严格等于undefined。
对象解构的注意点:
1)如果要将一个已经声明的变量用于解构赋值,必须非常小心。
// 错误的写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error
上面代码的写法会报错,因为 JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。
// 正确的写法
let x;
({x} = {x: 1});
上面代码将整个解构赋值语句,放在一个圆括号里面,就可以正确执行。关于圆括号与解构赋值的关系,参见下文。
2)解构赋值允许等号左边的模式之中,不放置任何变量名。因此,可以写出非常古怪的赋值表达式。
({} = [true, false]);
({} = 'abc');
({} = []);
上面的表达式虽然毫无意义,但是语法是合法的,可以执行。
3)由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1
last // 3
上面代码对数组进行对象解构。数组arr的0键对应的值是1,[arr.length - 1]就是2键,对应的值是3。
3.字符串的解构赋值
字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
类似数组的对象都有一个length属性,因此还可以对这个属性解构赋值。
let {length : len} = 'hello';
len // 5
4.数值和布尔值的解构赋值
解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。
解构赋值的规则:
解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。