1. 数组的解构赋值

解构: ES6 中允许按照一定的模式从数组和对象中提取值,然后对变量进行赋值,这被称为解构(Destructuring).

1. 基本用法

本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予相应的值。

  • 完全解构
let [a, b, c] = [1, 2, 3];
console.log(a); // 输出1
let [a, b] = [1];
console.log(b); // 解构不成功时返回undefined
  • 不完全解构

    等号左边只匹配到等号右边的一部分。

    let [a, [b], c] = [1, [2, 3], 4];
    console.log(b); // 输出2,只匹配到右边的右边数组[2, 3]中的2
  • 不能解构情况

    如果等号右边不是可遍历的解构,或者说等号右边的值或是转换为对象以后也不具备 Iterator 接口,那么就会解构失败。

    let [a] = 1;
    let [a] = false;
    let [a] = NaN;
    let [a] = undefined;
    let [a] = null;
    let [a] = {}

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

2. 默认值

解构赋值允许指定默认值。

ES6内部使用严格相等运算符(===)判断数组的某个位置是否有值。所以,如果一个数组成员不严格等于undefined,默认值是不会生效的。

let [a = 2] = [null];
// a = null
let [a = 2] = [];
// a = 2

如果默认值是一个表达式,那么这个表达式是惰性求值的

function f() {
return 2;
}
let [a = f()] = [1];
// a = 1, f函数不会执行 let [a = f()] = [];
// a = 2, f函数会执行

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

let [x = 1, y = x] = [];
// x = 1, y = 1
let [x = y, y = 1] = [];
// ReferenceError,在使用变量y时还并没有声明

2. 对象的解构赋值

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

举例说明:

let {foo:bar} = {foo:"aaa"};
console.log(bar); // bar = "aaa"
console.log(foo); // ReferenceError, foo is not defined
console.log({foo:bar}.foo); // {foo:bar}.foo = "aaa"

上面代码中 foo 是匹配的模式,通过 foo 匹配到对象 {foo:bar}foo 属性的值( bar 变量),然后将值赋给 bar 变量,这样对象 {foo:bar}foo 属性就有值了,即 bar 的值 "aaa".

// 实际上
let {foo1, foo2} = {foo1:"aaa", foo2:"bbb"};
// 是下面语句的简写形式
let {foo1:a, foo2:b} = {foo1:"aaa", foo2:"bbb"};

对象的解构也可以指定默认值,默认值生效的条件是,对象的属性值严格等于undefined

let {x = 3} = {x: undefined};
// x = 3
// 上面的语句等价于
let {x:x = 3} = {x: undefined};
// x = 3
// {x:x = 3} = 3 let {x = 3} = {x: null};
// x = null

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

let {foo: {bar}} = {bar: 'bar'};
// 报错,因为foo = {bar} = undefined,{bar}对象中的bar属性在解构时会报错,因为{bar}是undefined,undefined是不能转换为对象的,对undefined取bar属性会报错。
// 和下面的代码原理一样:
let obj = {bar: "bar"};
obj.foo.bar // 报错,因为obj.foo = undefined,对undefined取属性会报错。
"bar".foo // undefined,不会报错,因为字符串可以转换为对象

在将已经声明的变量进行解构赋值时,要注意解构赋值语句不能直接写在行首

let x;
{x} = {x: 1}; // 报错,这个地方不是很懂
// 书上的解释是:JS引擎将{x}理解成一个代码块,从而发生语法错误。
// 若想避免这个错误,可以这样写:
({x} = {x: 1});

3. 字符串的解构赋值

字符串可以解构赋值是因为字符串可以转换成一个类似数组的包装对象。

let [a, b, c, d, e] = "hello";
// a = 'h' b = 'e' c = 'l' d = 'l' e = 'o'

由于类似数组的包装对象有一个 length 属性,因此在解构赋值时可以利用这个属性。

let {length: len} = 'hello';
// len = 5

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

解构赋值时,如果等号右边是数值或布尔值,则会先转为对象

let {toString: s} = 123;
console.log(s === Number.prototype.toString) // true

数值 123 被转换为对象,数值对象中有 toString 方法,与 toString 匹配,变量 s 中存储的是 toString 方法,该方法就是 Number 原型对象中的 toString 方法。

5. 函数参数的解构赋值

函数参数的解构也可以使用默认值

function f({x = 0, y = 0} = {}) {
return {x, y};
}
console.log(f({x: undefined, y: 1}));
// 输出: {0, 1}

详细过程:调用函数f后,{x = 0, y = 0}={x:undefined,y:1}

由于x是undefined,故x使用默认值即x=0,由于y:1故通过解构赋值后y=1.

之前的误区:注意是解构赋值,并不是对象之间的赋值。

再看下面这个例子:

function f({x, y} = {x: 0, y: 0}) {
return {x, y};
}
console.log(f({x: undefined, y: 1}));
// 输出: {undefined, 1}
// 调用函数后,{x,y}={x:udefined,y:1},解构赋值后x=undefined,y=1
console.log(f({x: 1, y: 1}));
// 输出: {1, 1}
// 调用函数后,{x,y}={x:1,y:1},解构赋值后x=1,y=1
console.log(f({}));
// 输出: {undefined, undefined}
// 调用函数后,{x,y}={}={undefined,undefined},解构赋值后x=undefined,y=undefined
console.log(f());
// 输出: {0, 0} 当不传递实参时,形参的值是原有的值
// 调用函数后,{x,y}={x:0,y:0},解构赋值后x=0,y=0

再次重申一下 {x,y}={x:1,y:2} 这种形式是解构赋值,千万不要理解成对象之间的赋值!

6. 圆括号问题

对于编译器而言,一个式子到底是模式还是表达式,没有办法一开始就知道,必须解析到(或解析不到)等号才能知道

  • 不能使用圆括号的情况

    1. 变量声明语句
    2. 函数参数
    3. 赋值语句表达式
  • 可以使用圆括号的情况

    赋值语句中的非模式部分可以使用圆括号。

    [(a)] = [3]; // a并不是模式
    ({ p: (d) } = {}); // p是模式,d并不是模式

建议:无论什么情况都尽量不要在模式中使用圆括号

7. 解构赋值的作用

  1. 交换变量的值

    let a = 1;
    let b = 2;
    [a, b] = [b, a];
  2. 方便处理函数返回值

    function f([x, y]) {
    return [x+1, y+2];
    }
    let [a, b] = f([1, 1]);
  3. 函数参数定义

    解构赋值可以方便地将一组参数与变量名对应起来。

    function f1({x, y, z}){
    return x+y+z;
    }
    f1({y: 1, z: 2, x: 3 }); // 可以做到实参没有次序
  4. 提取JSON数据

    可以很方便地从JSON中提取需要的数据。

    let JSON = {
    name: "happyCoding1024",
    age: 18,
    hobby: "coding"
    }
    let [name, age, hobby] = JSON;
  5. 函数参数默认值

    非常简化方便地使用函数参数默认值。

    function f([x=0,y=0] = []){
    return x+y;
    }
    f([]); // 当传入的是undefined时,就会使用默认值
  6. 遍历Map结构

    任何部署了 Iterator 接口的对象都可以用 for...of 循环遍历。Map 结构原生支持 Iterator 接口,配合变量的解构赋值获取键名和键值非常方便。

    let map = new Map();
    map.set('first', 'hello');
    map.set('second', 'world');
    for (let [key, value] = map){
    console.log(key + "is" + value);
    }
  7. 输入模块的指定方法

    加载模块时,往往需要制定输入的方法,解构赋值使得输入语句非常清晰。

    const {SourceMapConsumer, SourceNode} = require("source-map");

ES6 中变量的解构赋值的更多相关文章

  1. ES6中变量的解构赋值

    1.数组的解构赋值 基本用法 ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring). 输出: 上面代码表示,可以从数组中提取值,按照对应位置,对变 ...

  2. es6之变量的解构赋值

    es5中通常我们声明变量都是以下的方式: var a = 10; var b = 20; var c = 30; //或者 var a = 10,b = 20,c = 30; //或者 var arr ...

  3. es6分享——变量的解构赋值

    变量的解构赋值:ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring). 以前的写法: var a = 1; var b = 2; es6允许的写法 ...

  4. ES6 继续 变量的解构赋值

    春节放假这几天,感觉跟梦一样,瞬间就过去了.现在上班的前几天,都感觉有点不真实,不过看到口袋里的钱,就知道,是真真实实的度过了这个假期. 现在得开始重新工作了: 变量的解构赋值 ES6 允许按照一定模 ...

  5. ES6入门——变量的解构赋值

    1.数组的解构赋值 以前为变量复制,只能直接指定值.现在ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring). 本质上,这种写法属于模式匹配,只要等 ...

  6. es6系列-变量的解构赋值

    git地址: https://github.com/rainnaZR/es6-study/tree/master/src/destructuring 变量的解构赋值 变量的解构赋值: 数组, 对象, ...

  7. ES6基础-变量的解构赋值

    作者 | Jeskson 来源 | 达达前端小酒馆 解构赋值: 数组的解构赋值,对象的解构赋值,字符串的解构赋值,数值与布尔值的解构赋值,函数参数的解构赋值. 开发环境准备: 编辑器,VS Code, ...

  8. 【ES6】变量的解构赋值

    1. 数组 var [a, b, c] = [1, 2, 3]; let [a, [b], d] = [1, [2, 3], 4]; 默认值生效的条件是,对象的属性值严格等于undefined. [x ...

  9. js中 变量的解构赋值

    es6新特性, 提取数组或对象中的值,按照对应位置, 为变量赋值. let [a, b, c] = [1, 2, 3]; 交换变量的值变得容易 let x = 1; let y = 2; [x, y] ...

随机推荐

  1. 04_Hibernate检索方式

    一.Hibernate检索方式概述 OID检索方式:按照对象的OID来检索对象(get/load) HQL检索方式:使用面向对象的HQL查询语言 QBC检索方式:使用QBC(Query By Crit ...

  2. Python基础---序列对象

    一.序列简介 数据结构是通过某种方式组织在一起的元素的集合. 容器(Container)是一种Python的数据结构,基本上是包含其他对象的任意对象.序列和映射(如字典)是两类主要的容器.集合(Set ...

  3. python 编码问题:'ascii' codec can't encode characters in position 的解决方案

    报错: 'ascii' codec can't encode characters in position 8-50: ordinal not in range(128) Python在安装时,默认的 ...

  4. Mybatis的插件 PageHelper 分页查询使用方法

    参考:https://blog.csdn.net/ckc_666/article/details/79257028 Mybatis的一个插件,PageHelper,非常方便mybatis分页查询,国内 ...

  5. NOIP2018崩崩记

    比赛前,做做往年的题目,嗯,似乎都很水,400+绝对没问题,如果完全发挥,起码500+. 然而-- Day0 这天是运动会,信息学的同学们向老师请假来机房. 然后我在机房里刷往届的题目,信心倍增. 最 ...

  6. std::unique_lock与std::lock_guard区别示例

    std::lock_guard std::lock_guard<std::mutex> lk(frame_mutex); std::unique_lock<std::mutex> ...

  7. 《Python机器学习及实践:从零开始通往Kaggle竞赛之路》

    <Python 机器学习及实践–从零开始通往kaggle竞赛之路>很基础 主要介绍了Scikit-learn,顺带介绍了pandas.numpy.matplotlib.scipy. 本书代 ...

  8. python简单爬豆瓣电影排名

    爬豆瓣电影 网站分析: 1 打开https://movie.douban.com,选择  [排行榜],然后随便选择一类型,我这里选择科幻    2 一直浏览网页,发现没有下一的标签,是下滑再加载的,可 ...

  9. [转载] DDK中VPORT Mini-Driver的使用说明

    学习下. 原文地址:DDK中VPORT Mini-Driver的使用说明作者:跳皮筋的小老鼠 要使用TI DDK中实现的VPORT驱动程序,首先需要在程序中提供VPORT_PortParams类型的参 ...

  10. C#获取C# DLL中的指定接口的所有实现实例 - qq_19759475的博客 - CSDN博客

    原文:C#获取C# DLL中的指定接口的所有实现实例 - qq_19759475的博客 - CSDN博客 public static List<T> CreateTarInterface& ...