【ES6】变量的解构赋值

变量的解构赋值 浅拷贝

数组

对象

字符串

Number / Boolean

函数参数

解构赋值的注意点

解构赋值的规则是:只要等号右边的值不是对象或数组,就先将其转为对象。

  1. 模式匹配:只要等号两边的模式相同,左边的变量就会被赋予对应的值。
  2. 不完全解构:等号左边的模式,只匹配一部分等号右边的数组。这种情况下,解构依然可以成功。
// 模式匹配
let [a, [b, c], d] = [1, [2, 3], 4]; // a=1 b=2 c=3 d=4

let [x, ,y] = [1, 2, 3]; // x=1 y=3

// 不完全解构
let [i, j] = [1, 2, 3]; // i=1 j=2

// 解构不成功
let [a, b] = [1]; // a=1 b=undefined(b解构不成功)

let [x] = []; // a=undefined(x解构不成功)

如果解构不成功,变量的值就等于 undefined

如果等号的右边不是数组(或者严格地说,不是可遍历的结构)那么将会报错。

// 报错
let [x] = 1;
let [x] = false;
let [x] = NaN;
let [x] = undefined;
let [x] = null;
let [x] = {};

上面的语句都会报错,因为等号右边的值,要么转为对象以后不具备 Iterator 接口(前五个表达式),要么本身就不具备 Iterator 接口(最后一个表达式)。

let { prop: x } = undefined; // 报错
let { prop: y } = null; // 报错

undefined 和 null 无法转为对象,对其解构会报错。

let [x, y, z] = new Set(['a', 'b', 'c']); // x: "a"

事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。

解构赋值允许指定默认值,当严格等于 undefined 时默认值才生效。

let [x, y] = [1]; // x=1 y=undefined
let [x, y = 3] = [1]; // x=1 y=3(y 解构不成功,等于 undefined,取默认值)

let [x = 1] = [null]; // x=null(null !=== undefined,默认值不生效)

let [x = 1, y = x] = []; // x=1 y=x=1
let [x = y, y = 1] = []; // 报错,x 使用变量 y 作为默认值,但是变量 y 还未声明

let { x: y = 3 } = {}; // y=3(y 解构不成功,等于 undefined,取默认值)
let { x: y = 3 } = { x: 5 }; // y=5

默认值可以引用解构赋值的其他变量,但该变量必须已经声明。

以上最后两个对象解构,其中 x 只是模式,不是变量。

数组解构

数组解构是根据索引匹配的。

let [x, y] = [1, 2]; // x=1 y=2

对象解构

对象解构是根据属性名匹配的。对象的解构赋值可以取到继承的属性。

let { name, age } = { name: '张三', age: 18 }; // name='张三' age=18
// 其实这是缩写,实际上是:let { name: name, age: age } = { name: '张三', age: 18 };

let { name: firstName, familyName: lastName } = { name: 'f', familyName:'l' }; // firstName="f" lastName="l" 如果打印 name 和 familyName 会报错:is not defined

对象的解构赋值:是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。

注意:以上第一个例子是缩写形式。第二个例子中 name, familyName 是模式,不是变量,因此不会被赋值。

// 在 obj 对象中定义了加一、减一两个方法
let obj = {
  add: (num) => {
    return ++num;
  },
  reduce: (num) => {
    return --num;
  }
}
// 通过调用 obj 中的方法计算 5+1 和 5-1 的值
let { add, reduce } = obj;
console.log(`5+1=${add(5)}; 5-1=${reduce(5)}`); // 5+1=6; 5-1=4

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

let { obj: { name } } = { age: 18 }; // 报错(obj = undefined)

如果解构模式是嵌套的对象,而且子对象所在的父属性不存在,那么将会报错。

字符串解构

字符串也可以解构赋值,此时被转为一个类似于数组的对象。

let [a, b] = "Hi"; // a=H b=i

let { length: len } = "Hi"; // len=2

类似数组的对象都有一个 length 属性,因此还可以对这个属性解构赋值。

数值和布尔值的解构

解构时,会先转为对象。

函数参数的解构

函数参数,也可以解构赋值。undefined 会触发函数参数的默认值。

function add([x, y]) {
  return x + y;
}

这个函数参数是一个数组,在传入参数的那一刻,已经对数组进行解构,获取了 x 和 y 的值。

const arr = [[1, 2], [3, 4]];
const rs = arr.map(([x, y]) => {
  console.log("x", x, "y", y); // x=1 y=2; x=3 y=4
  return x + y;
});
console.log(rs); // [3, 7]  length: 2

这是对一个二维数组的遍历,二维数组中每一个item都被解构赋值给 x, y

item = [1, 2],于是 x = 1, y = 2, x + y = 3

item = [3, 4],于是 x = 3, y = 4, x + y = 7

function add({ x = 1, y = 1 } = {}) {
  console.log(x, y);
  return x + y;
}

const obj = { x: 3, y: 1 };
console.log( add(obj) ); // 4 (x = 3, y = 1)
console.log( add({}) ); // 2(传入的参数是一个空对象,于是x = 1, y = 1)

以上add函数参数是一个对象,如果传入的参数是一个空对象,当对其解构时,x = undefined, y = undefined, 于是 x, y 取其默认值(x = 1, y = 1)。

function reduce({ x, y } = { x: 0, y: 0 }) {
  console.log(x, y);
  return x - y;
}
const obj2 = {};
console.log(reduce(obj)); // NaN (x = undefined, y = undefined)

以上是为reduce函数参数指定默认值,而不是为变量 x 和 y 指定默认值,所以当传入一个空对象时,不会触发参数默认值,于是 x = undefined, y = undefined (在传入的对象中未定义 x, y)。

解构赋值的注意点

可以使用圆括号的情况只有一种:赋值语句的非模式部分,可以使用圆括号。变量声明语句、函数参数、赋值语句的模式都不能使用圆括号。

let [(a)] = [3]; // 报错,变量声明语句不能使用圆括号
[(i)] = [2]; // 正确,这是赋值语句,其圆括号都不属于模式的一部分
({ p: (d) } = {}); // 正确,解释同上
posted @ 2021-10-14 11:28  等等啦  阅读(51)  评论(0)    收藏  举报