前言

该篇笔记是第二篇 变量的解构赋值。
这一章原文链接: 变量的解构赋值

解构赋值

ES6 容许依照肯定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。

解构赋值是对赋值运算符的扩大。
这是一种针对数组或者对象进行模式匹配,而后对其中的变量进行赋值。
在代码书写上简洁且易读,语义更加清晰明了;也不便了简单对象中数据字段获取。

数组的解构赋值

为变量赋值。

let sample1 = 1;let sample2 = 2;let sample3 = 3;

下面代码应用ES6的数组解构赋值能够写成上面这样。从数组中提取值,依照对应地位,对变量赋值。

let [sample1, sample2, sample3] = [1, 2, 3]; console.log(sample1, sample2, sample3); // 1, 2, 3

这种写法属于“模式匹配”,只有等号两边的模式雷同,右边的变量就会被赋予对应的值。
下面代码在申明变量同时进行了赋值,ES6也能够先申明变量再进行解构赋值,

let sample1, sample2, sample3;  // 先申明[sample1, sample2, sample3] = [1, 2, 3];console.log(sample1, sample2, sample3);  // 1, 2, 3

数组解构

有几种状况

  • 胜利解构

    • 齐全解构赋值
    • 不齐全解构赋值
    • 嵌套数组解构赋值
    • 变量申明并赋值解构
    • 先申明变量再进行解构赋值
  • 不胜利解构

留神:

  • 数组模式解构赋值 等号左边必须为可遍历构造,也就是说具备 Iterator 接口的数据结构。
  • 数组模式解构赋值 须要依照对应地位,对对象赋值。
  • 数组模式解构赋值 不胜利变量的值等于undefined
  • 数组模式解构赋值 的数组能够是多维数组。
  • 数组模式解构赋值 不必将等号左边的数组全副解构进去。
  • 数组模式解构赋值 容许等号右边模式不全副匹配等号左边的数组。
// 解构胜利let [sample1, [sample2, sample3]] = [1, [2, 3]]; console.log(sample1, sample2, sample3); // 1, 2, 3// 解构不胜利,变量的值就等于undefined。let [sample] = []; // sample 的值为 undefined let [sample1, sample2] = [1]; // sample2 的值为 undefined // 如果等号左边不是数组,也就是不可遍历构造,将会报错let [sample] = 1;  // 间接报错,因为等号左边的值是个字面量不可遍历
let sample1, sample2, sample3, sampleN;  // 先申明变量再进行解构赋值[[sample1, sample2], sample3, ...sampleN] = [[1, 2], 3, 4, 5]; // 嵌套数组console.log(sample1, sample2, sample3, sampleN); // 1 2 3 [4, 5]let [sample11, sample12] = [1, 2, 3]; // 变量申明并赋值解构let [sample21, ,sample23] = [1, 2, 3];console.log(sample11, sample12); // 不齐全解构 1 2console.log(sample21, sample23); // 不齐全解构 1 3

默认值

当你不想从数组中解构出的值为undefined,解构赋值容许指定默认值。

留神:

  • 当一个数组成员严格等于undefined,默认值才会失效。
  • 默认值不肯定为字面量,也能够援用解构赋值的其余变量,但该变量必须已申明。
  • 默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值。
// 当 值 不存在时,默认值失效let [sample1 = 10, sample2 = 11] = [2];console.log(sample1, sample2); // 2 11 // 当 值 === undefined 时,默认值才会失效let [sample10 = 10, sample11 = 11, sample13 = 12] = [undefined, "", null];console.log(sample10, sample11, sample13); // 10, , null, let [sample21 = 1, sample22 = sample21] = [];console.log(sample21, sample22);let sample30 = 31;let [sample31 = sample30, sample32 = 3] = [];console.log(sample31, sample32);

对象的解构赋值

对象解构

数组的解构赋值与对象的解构赋值有很大区别

留神:

  • 对象的解构赋值不再和程序无关,是与变量名无关,变量必须与属性同名,能力取到正确的值。
  • 对象的解构赋值是依据对象key值进行匹配。
  • 如果解构不胜利,那么值为undefined
  • 和数组解构赋值一样,能够对嵌套构造的对象进行解构赋值。

表达式等号左右两边,都要有相互匹配的属性值,能力将左边匹配胜利keyvalue值赋值给右边绝对应keyvalue,右边的value值作为变量。

let { sample: sample, sample1: sample2 } = { sample: 10, sample1: 11 }console.log(sample); // 10console.log(sample1) // 报错 sample1 is not definedconsole.log(sample2) // 11

ES6 对对象进行了扩大,对象里的属性与value值能够简写(当前会提到,目前只有晓得能够这样用),
ES6 容许在大括号外面,间接写入变量和函数,作为对象的属性和办法。这样的书写更加简洁。
当属性名与值或办法名雷同时,能够简写为一个。

const { log: log } = console; // 能够解构现有对象log('hello'); // hello// 下面代码能够简写为上面const { log } = console;log('hello') // hello

在嵌套的对象中应用解构赋值。

// 多重嵌套,还能够嵌套数组let obj = {  sample: [    'Hello',    { sample1: 'World' }  ]};let { sample: [sample, { sample1 }] } = obj; console.log(sample,sample1); // Hello World// 或者像这样?给数组或对象增加新内容let obj = {};let arr = [];({ sample: obj.a, sample1: arr[0] } = { sample: 123, sample1: true });console.log(obj); // {a: 123}console.log(arr); // [true]

默认值

和数组解构赋值默认值相似,对象的默认值

留神

  • 当一个对象的属性严格等于undefined,默认值才会失效。
  • 默认值不肯定为字面量,也能够援用解构赋值的其余变量,但该变量必须已申明。
// 当 对象的属性值 不存在时,默认值失效let {sample1 = 10, sample2 = 11} = {sample1:2};console.log(sample1, sample2); // 2, 11 //当 对象的属性值 === undefined 时,默认值才会失效let { sample10 = 10, sample11 = 11, sample12 = 12 } =     { sample10: "", sample11: undefined, sample12: null };console.log(sample10, sample11, sample12); // 11, , null// 默认值为变量let {sample21 = 1, sample22 = sample21} = {};console.log(sample21, sample22); // 1, 1let sample30 = 31;let {sample31 = sample30, sample32 = 3} = {};console.log(sample31, sample32); // 31, 3

留神

  1. 如果要将一个曾经申明的变量用于解构赋值,必须十分小心。
  2. 解构赋值容许等号右边的模式之中,不搁置任何变量名。
  3. 因为数组实质是非凡的对象,因而能够对数组进行对象属性的解构。
// 1. 语法错误let sample;{sample:sample} = {sample: 1}; // 间接报错/*     因为 JavaScript 引擎会将{sample}了解成一个代码块,从而产生语法错误。只有不将大括号写在行首,防止 JavaScript 将其解释为代码块,能力解决这个问题。*/// 2. 尽管无意义然而非法({} = [true, false]);({} = 'abc');({} = []);// 3. 数组应用对象的解构赋值,let { 0: sample0, 1: sample1 } = [1, 2];console.log(sample0, sample1); // 1, 2

字符串的解构赋值

字符串也能够解构赋值。
当字符串进行解构赋值的时候,字符串被转换成了一个类数组。
类数组也有length属性,所以还能够通过这个形式获取字符串的长度

let { length } = 'sample';console.log(length); // 6

数值和布尔值的解构赋值

解构赋值的规定是,只有等号左边的值不是对象或数组,就先将其转为对象。
因为**undefined****null**无奈转为对象,所以对它们进行解构赋值,都会报错。

// 数值与布尔值 进行解构赋值let { toLocaleString: sampleNum } = 111;console.log(sampleNum === Number.prototype.toLocaleString);let { toString: sampleBol } = true;console.log(sampleBol === Boolean.prototype.toString);// undefined 和 null 进行解构赋值let { prop: x } = undefined; // 间接报错 TypeErrorlet { prop: y } = null; // 间接报错 TypeError

函数参数的解构赋值

函数参数进行解构赋值,函数参数须要为可解构赋值的解构。

// 参数为数组时,参数在传入函数的时候,数组参数就被解形成变量 sample1 和 sample2 。function addNumberArr([sample1, sample2]) {  return sample1 + sample2;}console.log(addNumberArr([4, 4])); // 8// 参数为对象时,函数通过对这个参数进行解构 失去变量 sample1 和 sample2 的值。function addNumberObj({ sample1, sample2 }) {  return sample1 + sample2;}console.log(addNumberObj({ sample1: 10, sample2: 20 })); // 30

函数参数的解构也能够应用默认值。

// 函数通过对这个参数进行解构,失去变量sample1和sample2的值。// 如果解构失败,sample1和sample2等于默认值。function sample({ sample1 = 0, sample2 = 0 } = {}) {  console.log([sample1, sample2])  return [sample1, sample2];}sample({ sample1: 1, sample2: 2 }); // [1, 2]sample({ sample1: 1 }); // [1, 0]sample({}); // [0, 0]sample(); // [0, 0]

圆括号问题

什么是圆括号问题呢?

原来在编译器中,无奈在解析到等号之前辨认一个式子为表达式还是解构赋值等号右边局部,也就是模式匹配中右边的key(属性)值。那么如果辨认到了圆括号后,编译器该依照什么形式去解决圆括号呢?

ES6 规定,只有有可能导致解构的歧义,就不得应用圆括号。
阮一峰老师倡议只有有可能,就不要在模式中搁置圆括号。

留神:以下三种状况不能应用圆括号

  1. 变量申明语句
  2. 函数参数也属于变量申明,因而不能带有圆括号。
  3. 赋值语句的模式

下面三种状况应用圆括号间接报错。

// 1. 变量申明语句let [(sample)] =[1]; // 间接报错let { sample: ({ sample1: sample1 }) } = { sample: { sample1: 2 } }; // 间接报错// 2.  函数参数也属于变量申明,因而不能带有圆括号。function sampleFn([(sample)]) { return sample; } // 间接报错// 3. 赋值语句的模式({ sample2: sample21 }) = { sample2: 42 }; // 间接报错[({ sample3: sample31 }), { sample4: sample41 }] = [{}, {}];

只有一种状况能够应用圆括号
不能有申明语句,赋值语句的非模式(属性名)局部,能够应用圆括号。

({ sample: (sample) } = {}); // 正确console.log(sample); // undefined

解构赋值的用处

解构赋值次要还是用在对象和数组上,

  1. 替换变量的值

不必长期变量,怎么替换两个变量的值?能够应用解构赋值简略实现。

// 数组的解构赋值let sample1 = 2;let sample2 = 4;[sample1, sample2] = [sample2, sample1];console.log(sample1, sample2); // 4 , 2
  1. 函数多个返回值的解构赋值
// 解构函数返回的对象function sample() {  return [1, 2, 3];}let [sample1, sample2, sample3] = sample();console.log(sample1, sample2, sample3); // 1, 2, 3// 解构函数返回的对象function sample() {  return {    sample11: 1,    sample12: 2,    sample13: 3,  };}let {sample11, sample12, sample13} = sample();console.log(sample11, sample12, sample13); // 1, 2, 3
  1. 提取JSON数据

能够应用解构赋值一次性提取多个数据

let sampleJson = {  id: 11,  status: false,  data: [{ name: 'name1' }, { name: 'name2' }]}let { id, status, data } = sampleJson;console.log(id, status, data);// 11, false, [{ name: 'name1' }, { name: 'name2' }]
  1. 输出模块的指定办法
const { SourceMapConsumer, SourceNode } = require("source-map"); // 示例代码