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的值,此时默认值便不起作用。

原文地址:https://www.cnblogs.com/wenxuehai/p/10319749.html