ES6语法总结-变量的解构赋值

1、数组的解构赋值

基本用法

let [a, b, c] = [1, 2, 3]

上面代码可以从数组中取值,按照对应位置,对变量赋值

  • 本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值,如下:
let [a, [[b], c]] = [1, [[2], 3]]
a => 1
b => 2
c => 3

let [, , c] = [1, 2, 3]
c => 3

let [a, , c] = [1, 2, 3]
a => 1
c => 3

let [a, ...b] = [1, 2, 3]
a => 1
b => [2, 3] // 这里的b是一个数组

let [a, b, ...c] = [1]
a => 1
b => undefined
c => [] // 这里的c是一个空数组
// 如果解构不成功,那么变量的值就会是undefined
let [a] = []
a => undefined
let [a, b] = []
b => undefined
// 不完全解构:即等号左边的模式,只匹配一部分的等号右边的数组,这种情况下,解构依然可以成功
let [a, b] = [1, 2, 3]
a => 1
b => 2

let [a, [b], c] = [1, [2, 3], 4]
a => 1
b => 2
c => 4
// 如果等号的右边不是可遍历的结构,那么将会报错
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {}; // 这里的对象不具备Iterator接口
  • 只要某种数据结构具备Iterator接口,都可以采用数组形式的结构赋值

默认值

  • 解构赋值允许指定默认值
let [a = true] = []
a => true
  • ES6内部使用严格相等运算符,判断一个位置是否有值。只有一个数组成员严格等于undefined,默认值才会生效
let [a = 1] = [undefined]
a => 1

let [a = 1] = [null]
a => null
  • 默认值还可以是一个表达式,那么这个表达式是惰性求值,只有用到的时候,才会求值
function f() {
    console.log('aaa')
}
let [a = f()] = [1] // 因为a能够取到值,所以f函数不会执行
  • 默认值还可以引用解构赋值的其他变量,但该变量必须已声明
let [a = 1, b = x] = [1];
a => 1
b => 1

let [a = b, b = 1] = [1]; // 报错,b还未声明

2、对象的机构赋值

  • 数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性是无序的,变量必须与属性同名,才能取到正确的值
let {a, b} = {a: 1, b: 2}
a => 1
b => 2

let {a} = {b: 2, c: 3}
a => undefined
  • 对象的解构赋值,可以很方便的将现有对象的属性,赋值到某个变量
let { log, sin, cos } = Math
  • 如果变量名与属性名不同,必须写成下面这样:
let { a: c} = { a: 1, b: 2}
c => 1

这说明对象的解构赋值是以下形式:

// 对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者
// 所以前者a是模式,而后者a才是变量
let { a: a, b: b} = { a: 1, b: 2} 
  • 用于嵌套结构对象的结构
let obj = {
    p: [
        "hello",
        {y: :"world"}
    ]
}
let { p: [ hello, { y } ] } = obj
x => hello
y => world
// 上面的p是模式,如果要p是变量就不要接冒号
  • 前者是模式,后者是变量。这个概念很重要,也就意味着对象的结构赋值是先通过模式找到同名属性,然后赋值给变量。同时,等号左边是可以存在多次的解构赋值的。如下
let obj = {
    a: {
        b: {
            c: "c",
            d: "d"
        }
    }
}
let {a, a: {b}, a: {b: {c}}} = obj;
a => 第一层Object
b => 第二层Object
c => c
  • 嵌套赋值
let obj = {};
let arr = [];
({a: obj.a, arr: arr[0]} = {a: 'a', arr: 'arr'}) // 注意这里没有let命令,而且使用了括号包裹起来了
  • 对象的解构赋值也可以取到继承的属性
const obj1 = {};
const obj2 = { foo: 'bar' };
Object.setPrototypeOf(obj1, obj2);

const { foo } = obj1;
foo // bar

默认值

  • 对象解构设置默认值
// 默认值生效的条件是,对象的属性值严格等于`undefined`
let { a = 1 } = {}
a => 1

let { a, b = 2 } = { a = 1 }
a => 1
b => 2

let { a: a1 = 1 } = {}
a1 => 1

let { a: a1 = 1 } = { a = 2 }
a1 => 2

注意点

  • 如果将一个已声明的变量用于解构赋值
// 错误写法
let x;
{ x } = { x: 1 }

// 上面的写法是错误,JavaScript引擎会理解{ x }是一个代码块。只有不将{ x }卸载行首,才能解决问题
let x;
({ x } = { x: 1 })
  • 解构赋值允许等号左边的模式之中,不放置任何变量名。因此可以写出非常古怪的赋值表达式
// 下面的表达式虽然毫无意义,但是语法是合法的,可以执行
({} = [true, false])
({} = 'abc');
({} = []);
  • 由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构
let arr = [1, 2, 3];
let { 0, first, [arr.length - 1]: last } = arr;
first => 1
last => 3

3、字符串的解构赋值

let { a, b, c } = "abc"
a => a
b => b
c => c

4、数值和布尔值的解构赋值

  • 解构赋值时,如果等号右边是数值和布尔值,则会先转为对象
let {toString: s} = 123;
s === Number.prototype.toString // true 
let {toString: s} = true;
s === Boolean.prototype.toString // true

// 由于`undefined`和`null`无法转为对象,所以对它们进行解构赋值,都会报错
let { prop: x } = undefined; // TypeError let { prop: y } = null; // TypeError

5、函数参数的解构赋值

function add([a, b]) {
    return a + b;
}
add([1, 2]) => 3

// 另一个例子
let arr = [[1, 2], [2, 3]].map(([a, b]) => a + b)
arr => [3, 5]
  • 函数参数解构使用默认值
// 参数解构的默认值
function move({a = 1, b = 2} = {}) {
    return [a, b];
}

move({a: 3, b: 5}); // => [3, 5]
move({a: 3}); // => [3, 2]
move({}); // => [1, 2]
move(); // => [1, 2]

// 指定move函数的参数的默认值,注意与上面的区别
move({a, b} = {a: 1, b: 2}) {
    return [x, y]
}
move(); // => [1, 2]
move({}); // [undefined, undefined]
move({a: 3}); // [3, undefined]
move({a: 3,b: 8}); // [3, 8] 

6、圆括号问题

不能使用圆括号的情况

  • 变量声明
// 全部报错,因为他们都是变量声明语句,模式不能使用圆括号
let [(a)] = [1];
let { a: (b)} = {};
let ({a: b}) = {};
let {(a: b)} = {};
let {(a): b} = {};
let { o: ({ p: p }) } = { o: { p: 2 } };
  • 函数参数
// 函数参数也属于变量声明,也不能使用圆括号
// 报错
function f([(a)]) {}
function f([a, (b)]) {}
  • 赋值语句的模式
// 报错
({a: b}) = { p: 34 };
([a]) = [5];

可以使用圆括号的情况

  • 赋值语句的非模式部分,可以使用圆括号
// 以下都正确,因为他们都是赋值语句,而非声明语句;其次他们的圆括号不属于模式的一部分
[(b)] = [3]; // 正确 
({ p: (d) } = {}); // 正确 
[(parseInt.prop)] = [3]; // 正确

你可能感兴趣的:(javascript)