ES6中的解构赋值
1、数组的解构赋值
1.1、基本用法
按照“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
let [a, b, c] = [1, 2, 3]; //a为1,b为2,c为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: []
如果左边的值匹配不上,就会被赋值为undefined
。
1.2、指定默认值
解构赋值允许指定默认值。ES6 内部使用严格相等运算符(===
),判断等号右边该位置是否有值。所以,等号右边该值严格等于undefined(空也等于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 = 1] = [undefined]; //x:1 let [x = 1] = [null]; //x:null
1.3、报错情况(等号右边不是数组、默认值引用未定义变量)
如果等号的右边不是数组(或者严格地说如果不是可遍历的结构),那么将会报错。
// 报错 let [foo] = 1; let [foo] = false; let [foo] = NaN; let [foo] = undefined; let [foo] = null; let [foo] = {};
默认值可以引用其他的变量,但该变量必须已经声明过,否则将会报错。
let [x = 1, y = x] = []; // x=1; y=1 let [x = 1, y = x] = [2]; // x=2; y=2 let [x = 1, y = x] = [1, 2]; // x=1; y=2 let [x = y, y = 1] = []; // ReferenceError: y is not defined 此时在x用y做默认值时,y还没有声明。
2、对象的解构赋值
2.1、基本用法
对象的解构与数组不太一样,数组的元素是按次序排列的,变量的取值由位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
let { foo, bar } = { foo: 'aaa', bar: 'bbb' }; //foo:"aaa" bar:"bbb" let { bar, foo } = { foo: 'aaa', bar: 'bbb' }; //foo:"aaa" bar:"bbb" 次序不影响赋值,变量名才影响 let { baz } = { foo: 'aaa', bar: 'bbb' }; //baz:undefined 变量名匹配不上将会赋值为undefined
如果变量名与属性名不一致,可以写成这样:
let { foo: baz } = { foo: 'aaa', bar: 'bbb' }; //baz:"aaa" let obj = { first: 'hello', last: 'world' }; let { first: f, last: l } = obj; //f: 'hello' l: 'world'
对象的解构赋值的内部机制,是先找到等号左边的同名属性,然后再赋给左边对应的变量。真正被赋值的是左边同名属性后面的变量,而不是那个同名属性。
2.2、默认值
对象的解构也可以指定默认值。
var {x = 3} = {}; //x: 3 var {x, y = 5} = {x: 1}; //x: 1 y: 5 var {x: y = 3} = {}; //y: 3 var {x: y = 3} = {x: 5}; //y: 5 var { message: msg = 'Something went wrong' } = {}; //msg: "Something went wrong"
默认值生效的条件是,等号右边对象的属性值严格等于undefined
。
var {x = 3} = {x: undefined}; //x: 3 var {x = 3} = {x: null}; //x: null
2.3、报错情况(给已经定义好的变量赋值可能会报错)
给已经定义好的变量进行解构赋值有可能会报错:
let a, b; {a, b} = {a: 123, b: 456}; // 报错显示:Uncaught SyntaxError: Unexpected token =
上面的代码将会报错,因为 JS 引擎遇到 {} 会当成一个代码块,语法规定,代码块语句不允许出现在赋值语句左侧。
所以解构赋值时' { '符号不能出现在一行的最前面。在添加小括号后可以将块语句转化为一个表达式,从而实现整个解构赋值过程。
let a, b; ({a, b} = {a: 123, b: 456}); console.log(a, b) // 123 456
2.4、解构赋值浅拷贝问题
解构赋值的拷贝是浅拷贝,如果一个键的值是复合类型的值(数组、对象、函数)、那么解构赋值拷贝的是这个值的引用,而不是这个值的副本。
let obj = { a: { b: 1 }, c: 100 }; let { ...x } = obj; //obj中 a 的值是对象,所以解构赋值时拷贝的是 a 的引用,而 c 的值是简单类型,所以obj.c改变不影响x obj.a.b = 2; obj.c = 200; console.log(x.a.b,c) // 2 100
3、函数参数的解构赋值
3.1、基本用法
function add([x, y]){ return x + y; } add([1, 2]); // 3
3.2、默认值
(1)普通参数默认值:
function show(age, name='www', c=false) { console.log(age, name, c); } show(); //undefined "www" false show(12); //12 "www" false show(12, 'aaa'); //12 "aaa" false show(12, 'aaa', true); //12 "aaa" true
(2)当函数的参数是一个对象时,默认值的写法:
function move({x = 0, y = 0} = {}) { return [x, y]; } move({x: 3, y: 8}); // [3, 8] move({x: 3}); // [3, 0] move({}); // [0, 0] move(); // [0, 0]
上面代码中,{x=0, y=0} 意思是x,y的默认值分别是0,后面的={}意思是如果函数没有传参时参数默认是{},而且由于前面给x,y默认值了,所以总的来说,参数的默认值是{x=0, y=0}。
如果没有写后面的={},直接 move() 这样调用将会报错,但其他形式的调用不会有问题。实际上后面的 ={} 才表示默认值。
注意,下面的写法会得到不一样的结果。
function move({x, y} = { x: 0, y: 0 }) { return [x, y]; } move({x: 3, y: 8}); // [3, 8] move({x: 3}); // [3, undefined] move({}); // [undefined, undefined] move(); // [0, 0]
上面的写法表示的是函数的参数默认是{x:0, y:0},但如果有参数的话即使参数只传x的值,此时默认值便不起作用。