解构赋值解析

458 阅读5分钟

ES6解构赋值解析

描述:

解构赋值是对赋值运算符的扩展。

他是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。

在代码书写上简洁且易读,语义更加清晰明了;也方便了复杂对象中数据字段获取。

解构赋值语法是一种 Javascript 表达式。通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。

解构模型:

在解构过程中,有两部分参与:

  • 解构的源,解构赋值表达式的右边部分。
  • 解构的目标,解构赋值表达式的左边部分。 在ES5中,开发者们为了从对象和数组中获取特定数据并赋值给变量,编写了许多看起来同质化的代码
let options = {
    age: 12,
    sex: 'boy'
};
// 从对象中提取数据
let age = options.age,
sex = options.sex;

  这段代码从options对象中提取repeat和save的值,并将其存储为同名局部变量,提取的过程极为相似

  如果要提取更多变量,则必须依次编写类似的代码来为变量赋值,如果其中还包含嵌套结构,只靠遍历是找不到真实信息的,必须要深入挖掘整个数据结构才能找到所需数据

  所以ES6添加了解构功能,将数据结构打散的过程变得更加简单,可以从打散后更小的部分中获取所需信息

一、对象结构

1、 一般的对象结构赋值

对象字面量的语法形式是在一个赋值操作符左边放置一个对象字面量;

let node = {
    type: "Identifier",
    name: "foo"
};
let { type, name } = node;
console.log(type); // "Identifier"
console.log(name); // "foo"

  在这段代码中,node.type的值被存储在名为type的变量中;node.name的值被存储在名为name的变量中。

2、无声明赋值

一个变量可以独立于其声明进行解构赋值。

var a, b;

({a, b} = {a: 1, b: 2});

注意:赋值语句周围的圆括号 ( ... ) 在使用对象字面量无声明解构赋值时是必须的。

{a, b} = {a: 1, b: 2} 不是有效的独立语法,因为左边的 {a, b} 被认为是一个块而不是对象字面量。

然而,({a, b} = {a: 1, b: 2}) 是有效的,正如 var {a, b} = {a: 1, b: 2}

你的 ( ... ) 表达式之前需要有一个分号,否则它可能会被当成上一行中的函数执行。

3、给新的变量名赋值

可以从一个对象中提取变量并赋值给和对象属性名不同的新的变量名。

var o = {p: 42, q: true};
var {p: foo, q: bar} = o;

console.log(foo); // 42
console.log(bar); // true

4、 结构默认值

变量可以先赋予默认值。当要提取的对象对应属性解析为 undefined,变量就被赋予默认值。

var {a = 10, b = 5} = {a: 3};
console.log(a); // 3
console.log(b); // 5

5、给新的变量命名并提供默认值]

一个属性可以同时 1)从一个对象解构,并分配给一个不同名称的变量 
                2)分配一个默认值,以防未解构的值是 `undefined`var {a:aa = 10, b:bb = 5} = {a: 3};
console.log(aa); // 3
console.log(bb); // 5

6、可嵌套可忽略

let obj = {p: ['hello', {y: 'world'}] }; 
let {p: [x, { y }] } = obj; // x = 'hello' // y = 'world'
let obj = {p: ['hello', {y: 'world'}] }; 
let {p: [x, { }] } = obj; // x = 'hello'

7、不完全解构

let obj = {p: [{y: 'world'}] };
let {p: [{ y }, x ] } = obj; 
// x = undefined // y = 'world'

8、剩余运算符

let {a, b, ...res} = {a: 10, b: 20, c: 30, d: 40};
// a = 10 // b = 20 // res = {c: 30, d: 40};

9、对象属性计算名和解构

计算属性名,如 object literals,可以被解构。

let key = "z";
let { [key]: foo } = { z: "bar" };

console.log(foo); // "bar"

10、通过提供有效的替代标识符,解构可以与不是有效的JavaScript标识符的属性名称一起使用。

 const foos = { 'kk-b': true };
 const { 'kk-b': kkb } = foos;
 console.log(kkb); // "true"

11、解构对象时会查找原型链(如果属性不在对象自身,将从原型链中查找)

// 声明对象 和 自身 self 属性
var obj = {self: 'hello'};
// 在原型链中定义一个属性 prot
obj.__proto__.prot = 'word';
// test
const {self, prot} = obj;
// self "hello"
// prot "word"(访问到了原型链)

二、数组结构

1、对象和数组逐个对应表达式,或称对象字面量和数组字面量,提供了一种简单的定义一个特定的数据组的方法。

var x = [1, 2, 3, 4, 5];

解构赋值使用了相同的语法,不同的是在表达式左边定义了要从原变量中取出什么变量。

var x = [1, 2, 3, 4, 5];
var [y, z] = x;
console.log(y); // 1
console.log(z); // 2

2、基本数组结构

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

3、变量声明并赋值时的解构

var foo2 = ["aa", "bb", "cc"];
var [aa, bb, cc] = foo2;
console.log(aa); // "aa"
console.log(bb); // "bb"
console.log(cc); // "cc"

4、变量先声明后赋值时的解构

通过解构分离变量的声明,可以为一个变量赋值。

var a, b;
[a, b] = [1, 2];
console.log(a); // 1
console.log(b); // 2

5、默认值

为了防止从数组中取出一个值为undefined的对象,可以在表达式左边的数组中为任意对象预设默认值。

var a, b;
[a=2, b=3] = [1];
console.log(a); // 1
console.log(b); // 3

6、交换变量

在一个解构表达式中可以交换两个变量的值。

没有解构赋值的情况下,交换两个变量需要一个临时变量

var a = 1;
var b = 2;
[a, b] = [b, a];
console.log(a); // 2
console.log(b); // 1

7、解析一个从函数返回的数组

从一个函数返回一个数组是十分常见的情况。解构使得处理返回值为数组时更加方便。

在下面要让 [1, 2] 成为函数的 f() 的输出值,可以使用解构在一行内完成解析。

function f() {
  return [1, 2];
}

var a, b;
[a, b] = f();
console.log(a); // 1
console.log(b); // 2

8、忽略某些返回值

function f() {
  return [1, 2, 3];
}

var [a, , b] = f();
console.log(a); // 1
console.log(b); // 3

全部返回值

[,,] = f();

9、 将剩余数组赋值给一个变量

当解构一个数组时,可以使用剩余模式,将数组剩余部分赋值给一个变量。

var [a5, ...b5] = [1, 2, 3];
console.log(a5); // 1
console.log(b5); // [2, 3]

10、可嵌套

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

11、不完全解构

let [a = 1, b] = [];
// a = 1, b = undefined