ES6解构赋值详解

时间:2022-09-05 13:11:50

文章转载自:http://www.zhufengpeixun.cn/article/167

解构赋值(destructuring assignment)语法是一个 Javascript 表达式,这种语法能够更方便的提取出 Object 或者 Array 中的数据。这种语法可以在接受提取的数据的地方使用,比如一个表达式的左边。有明确的语法模式来告诉我们如何使用这种语法提取需要的数据值。

Object 的解构

解构 Object:

const obj = { first: 'Jane', last: 'Doe' };
const {first: f, last: l} = obj;
// f = 'Jane'; l = 'Doe' // {prop} is short for {prop: prop}
const {first, last} = obj;
// first = 'Jane'; last = 'Doe'

解构能帮助更好地处理方法返回的对象:

const obj = { foo: 123 };

const {writable, configurable} = Object.getOwnPropertyDescriptor(obj, 'foo');

console.log(writable, configurable); // true true

Array 的解构

解构数组,对所有可遍历的值有效。

let foo = ["one", "two", "three"];

let [one, two, three] = foo;
console.log(one); // "one"
console.log(two); // "two"
console.log(three); // "three" const iterable = ['a', 'b'];
const [x, y] = iterable;
// x = 'a'; y = 'b' [x, y] = iterable; // window.x = 'a'; window.y = 'b';

同样的,解构数组也能帮助我们更好地处理函数返回值:

const [all, year, month, day] =
/^(\d\d\d\d)-(\d\d)-(\d\d)$/
.exec('2999-12-31');

而且,你也可以忽略你不感兴趣的返回值:

function f() {
return [1, 2, 3];
} let [a, , b] = f();
console.log(a); // 1
console.log(b); // 3

你也可以忽略全部返回值,不过似乎没啥用:

[,,] = f();

当解构一个数组时,可以使用剩余模式(拓展语句,Spread operator),将数组剩余部分赋值给一个变量。

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

在什么地方可以使用解构

解构可以在下面这些情景中使用,只展现了数组模式的演示,对象模式也是如此。

// 变量声明:
const [x] = ['a'];
let [x] = ['a'];
var [x] = ['a']; // 赋值: 下面这种情况将会在全局变量上添加一个 x 属性,值为‘a‘
[x] = ['a']; // 参数的定义:
function userId({id}) {
return id;
} function whois({displayName: displayName, fullName: {firstName: name}}){
console.log(displayName + "is" + name);
} var user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
}; console.log("userId:" + userId(user)); // "userId: 42"
whois(user); // "jdoe is John" function f([x]) { ··· }
f(['a']);

也可以在 for-of 循环中使用:

const arr = ['a', 'b'];
for (const [index, element] of arr.entries()) {
console.log(index, element);
}
// Output:
// 0 a
// 1 b

解构赋值的模型 patterns

在解构中,有下面两部分参与:

  • Destructuring source: 解构的源,将要被解构的数据,比如解构赋值表达式的右边部分。
  • Destructuring target: 解构的目标,比如解构复制表达式的左边部分。

解构的目标可以是下面三个的任意一个:

  • 赋值对象,Assigment Patterns。例如 x . 赋值对象通常来说是一个变量。但是在解构赋值中,你有更多的选择,稍后会讲到。
  • 对象模型,Object Patterns。比如:{first: «pattern», last: «pattern»}
  • 数组模型,Object Patterns。比如:[«pattern», «pattern»]

可以任意嵌套模型,而且是可以非常任性的嵌套。

const obj = { a: [{ foo: 123, bar: 'abc' }, {}], b: true };
const { a: [{foo: f}] } = obj; // f = 123

解构的 patterns 如何访问到值的内部结构?

在一个表达式 pattern = someValue 中,pattern是如何访问 someValue 的呢?

Object patterns 将 value 转换成 Object

在访问属性之前,object pattern 将解构的源数据(destructuing source)转换成对象。

const {length : len} = ‘abc’; // len = 3
const {toString: s} = 123; // s = Number.prototype.toString

使用“对象解构”的缺点

在这个过程中,强制转换成对象的过程不是通过 Object() 方法,而是通过内置的操作方法 toObject()。这两个操作处理undefined 和null的方式不太一样。

Object()方法将原始类型值转换成包装类型对象(wrapper object),原来的值原封不动。

> typeof Object('abc')
'object' > var obj = {};
> Object(obj) === obj
true

也会将undefined 和 null 转换成一个空的对象。

> Object(undefined)
{}
> Object(null)
{}

对比之下,当遇到 undefined 和null的时候,toObject()方法则会抛出一个错误。所以下面的解构是失败的:

const { prop: x } = undefined; // TypeError
const { prop: y } = null; // TypeError

因此,你可以使用空对象模型 {} 来检查一个值是否被强制转换成了一个对象。正如前面提到的规则,undefined和 null 将会抛出错误

({} = [true, false]); // OK, Arrays are coercible to objects
({} = 'abc'); // OK, strings are coercible to objects ({} = undefined); // TypeError
({} = null); // TypeError

表达式两边的括号是必须的,因为在 JavaScript 中,声明不能以花括号开始。

在可遍历的量中使用数组模型

数组解构使用一个迭代器来获取数据源中的元素。因此,你可以对任何可以遍历的值使用数组解构。

字符串是可遍历的:

const [x, ...y] = 'abc'; // x='a'; y=['b', 'c']

我们无法通过索引访问 Set 中的元素,但是可以通过迭代器。所以,数组解构能够在 Sets 上工作:

const [x,y] = new Set(['a', 'b']); // x='a'; y='b’;

Set的迭代器总是按照元素插入的顺序将元素返回,所以上述的解构返回的结果总是相同的。

使用“数组解构”的缺点

如果一个值有一个 key 为 Symbol.iterator 的方法,这个方法返回的是一个对象,那么这个值是可以遍历的。如果被解构的值不能遍历的,那么“数组解构”会抛出一个 TypeError 错误。

let x;
[x] = [true, false]; // OK, Arrays are iterable
[x] = 'abc'; // OK, strings are iterable
[x] = { * [Symbol.iterator]() { yield 1 } }; // OK, iterable [x] = {}; // TypeError, empty objects are not iterable
[x] = undefined; // TypeError, not iterable
[x] = null; // TypeError, not iterable

可以用一个空的数组模型 [] 来检查值是不是可遍历的:

[] = {}; // TypeError, empty objects are not iterable
[] = undefined; // TypeError, not iterable
[] = null; // TypeError, not iterable

默认值

默认值是可选的,在数据源中找不到对应的值时,如果设置了默认值,则匹配这个默认值作为匹配结果,否则返回 undefined。

const [x=3, y] = []; // x = 3; y = undefined。
const {foo: x=3, bar: y} = {}; // x = 3; y = undefined

undefined 也会触发默认值

当解构模式有匹配结果,且匹配结果是 undefined 时,也会使用默认值作为返回结果:

const [x=1] = [undefined]; // x = 1
const {prop: y=2} = {prop: undefined}; // y = 2

默认值是根据需要计算出来的

也就是说下面的解构:

const {prop: y=someFunc()} = someValue;

相当于:

let y;
if (someValue.prop === undefined) {
y = someFunc();
} else {
y = someValue.prop;
}

使用 console.log() 可以观察到:

> function log(x) { console.log(x); return 'YES' }
> const [a=log('hello')] = [];
> a
'YES'
> const [b=log('hello')] = [123];
> b
123

在第二个解构中,默认值没有触发,并且 log() 没有被调用。

默认值可以引用模式中的其他变量

默认值可以引用模式中的任何变量,包括相同模式中的其他变量:

const [x=3, y=x] = [];     // x=3; y=3
const [x=3, y=x] = [7]; // x=7; y=7
const [x=3, y=x] = [7, 2]; // x=7; y=2

但是,变量的顺序很关键,从左到右,先声明的变量不能引用后声明的变量,也就是左边的不能引用右边的。

const [x=y, y=3] = []; // ReferenceError

patterns 的默认值

到目前为止,我们所看到的都是模式中变量的默认值,我们也可以为模式设置默认值。

const [{prop: x} = {}] = [];

如果整个模式没有匹配结果,则使用 {} 作为数据源来匹配。

const { prop: x } = {}; // x = undefined

上面的例子中,x 为 undefined 可能还是不够直观。看下面这个例子:

const [{prop: x} = {props: 'abc'}] = []; // x=abc

对象解构的更多特性

属性,属性值的简写

如果属性值是一个变量,和属性的 key 相同,就可以忽略这个 key:

const { x, y } = { x: 11, y: 8 }; // x = 11; y = 8

// 等价于
const { x: x, y: y } = { x: 11, y: 8 };

计算后的属性的键

如果把表达式放入方括号中,可以用这个表达式声明属性的键:

const FOO = 'foo';
const { [FOO]: f} = {fooL 123}; // f = 123
这也使得可以使用 symbols 来做属性的键: // Create and destructure a property whose key is a symbol
const KEY = Symbol();
const obj = { [KEY]: 'abc' };
const { [KEY]: x } = obj; // x = 'abc' // Extract Array.prototype[Symbol.iterator]
const { [Symbol.iterator]: func } = [];
console.log(typeof func); // function

数组解构的更多特性

在解构的过程中可以跳过一些元素:

const [,,x,y] = [1,2,3,4]; // x= 3 y = 4;

剩余运算符 Rest operator (…)

剩余运算符可以将一个可遍历对象中剩余的元素提取到一个数组中。如果这个运算符在数组模式中使用,运算符必须放在最后:

const [x, ...y] = [1,2,3,4]; // x=1; y=[2,3,4];

要注意的时,拓展运算符(spread operator)与剩余操作符有着相同的语法 - 三个点。但是它们之间有区别:前者将数组变成多个元素;后者则用来解构和提取数据,多个元素压缩成一个元素。

如果运算符找不到任何元素,将会匹配一个空的数组,永远不会返回 undefined 或者 null。例如:

const [x, y, ...z] = ['a']; // x='a'; y=undefined; z

操作符不一定非要是一个变量,也可以使用模式:

const [x, ...[y, z]] = ['a', 'b', 'c']; // x = 'a'; y = 'b'; z = 'c'

解构的陷阱

在使用解构的时候,有两点要考虑清楚:

不能使用大括号作为声明语句的开头;

在解构的过程中,可以申明变量或者分配给变量,但是不能同时这么做;

解构的几个例子

在 for-of 中使用解构:

const map = new Map().set(false, 'no').set(true, 'yes');
for (const [key, value] of map) {
console.log(key + 'is' + value);
}

使用解构交换两个变量的值:

[a, b] = [b, a];

或者:

[a, b, c] = [c, a, b];

还可以分割数据:

const [first, ...rest] = ['a', 'b', 'c']; // first = 'a'; rest = ['b', 'c']

处理方法返回的数组更加方便:

const [all, year, month, day] = /^(\d\d\d\d)-(\d\d)-(\d\d)$/.exec('2999-12-31');

const cells = 'Jane\tDoe\tCTO'
const [firstName, lastName, title] = cells.split('\t');
console.log(firstName, lastName, title);

要注意的一点是:exec 等一些方法可能会返回 null,导致程序抛出错误TypeError,此时需要添加一个默认值:

const [, year, month, day] = /^(\d\d\d\d)-(\d\d)-(\d\d)$/.exec(someStr) || [];

文章转载自:http://www.zhufengpeixun.cn/article/167

ES6解构赋值详解的更多相关文章

  1. ES6(二)解构赋值详解

    详解一下之前的解构赋值 ①解构赋值中的"..." let [a,...b]= [1]; b // [] ...代表变量b去匹配剩余的所有元素返回一个数组 ,匹配不到时返回[] // ...

  2. ES6 解构赋值详解

    解构赋值是对赋值运算符的扩展,可以将属性/值从对象/数组中取出,赋值给其他变量. 一.数组的解构赋值 1.基本用法 只要等号两边的模式相同,左边的变量就会被赋予对应的值. let [a, [[b], ...

  3. 【ES6 】ES6 解构赋值--数组解构赋值

    定义 ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构 数组的解构赋值 以前,为变量赋值,只能直接指定值. let a = 1; let b = 2; let c = 3; ...

  4. 【ES6 】ES6 解构赋值--对象解构赋值

    对象的解构与数组有一个重要的不同. 数组的元素是按次序排列的,变量的取值由它的位置决定 而对象的属性没有次序,变量必须与属性同名,才能取到正确的值. 基本用法 如果解构失败,变量的值等于undefin ...

  5. 001-es6变量声明、解构赋值、解构赋值主要用途

    一.基本语法 1.1.声明变量的六种方法 参看地址:http://es6.ruanyifeng.com/#docs/let let:局部变量,块级作用域,声明前使用报错 var:全局变量,声明前使用 ...

  6. ES6笔记(3)-- 解构赋值

    系列文章 -- ES6笔记系列 解构赋值,即对某种结构进行解析,然后将解析出来的值赋值给相关的变量,常见的有数组.对象.字符串的解构赋值等 一.数组的解构赋值 function ids() { ret ...

  7. es6学习笔记--解构赋值

    昨天学习了es6语法中解构赋值,解构赋值在声明中和函数传参提高了灵活性和便捷性,值得掌握该语法. 概念: ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构.   数组的解构 ...

  8. es6入门2--对象解构赋值

    解构赋值:ES6允许按照一定规则从数组或对象中提取值,并对变量进行赋值.说直白点,等号两边的结构相同,右边的值会赋给左边的变量. 一.数组的解构赋值: 1.基本用法 let [a, b, c] = [ ...

  9. ES6学习之 解构赋值

    最近看了一个vue的项目,发现作者大量使用了ES6的语法,包括async, Promise, Set, Map还有一些解构赋值, 才发现自己对于ES6的语法缺乏了总结和运用,看得有点艰难,所以重新学习 ...

随机推荐

  1. Temporary-Post-Used-For-Style-Detection-Title-16761156

    Temporary-Post-Used-For-Style-Detection-Content-16761156 =-=-=-=-=Powered by Blogilo

  2. [转发] 理解 oauth 2.0

    原文: http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html oauth 的各种编程语言实现: http://oauth.net/2/ 理解OAu ...

  3. json string 与object 之间的转化

    1.将json string转化成object 1: public static T GetObjectFromJson<T>(string jsonString) 2: { 3: Dat ...

  4. HDU 3687 National Day Parade &lpar;暴力&rpar;

    题意:给定 n 个人,在 n 列,问你移动最少的距离,使得他们形成一个n*n的矩阵. 析:这个题本来是要找中位数的,但是有特殊情况,所以改成暴力了,时间也很短,就是从第一个能够放左角的位置开始找,取最 ...

  5. OracleL

    DDL  : Data Definition Language (DDL) statements are used to define the database structure or schema ...

  6. 转:微博CacheService架构浅析

    文章来自于:http://www.infoq.com/cn/articles/weibo-cacheservice-architecture 微博作为国内最大的社交媒体网站之一,每天承载着亿万用户的服 ...

  7. PowerShell常用的属性

    get-location | get-member  -membertype  property -------获取对象的属性---------- 获取对象特定的成员, 湖区.Net Framwork ...

  8. 系统装机硬盘格式 &gt&semi;&gt&semi; GPT或者UEFI

    预装Win8系统的电脑,硬盘都是采用这种分区格式,因为出厂安装时,是以Uefi方式启动安装的. 简单的办法,仍安装Win8系统:或者是转换磁盘分区格式为MBR,不用任何软件就可实现,需要重建分区表,会 ...

  9. 【Unity Shaders】Diffuse Shading——漫反射光照改善技巧

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  10. 《阿里巴巴 Java开发手册》读后感

    前言 只有光头才能变强 前一阵子一直在学Redis,结果在黄金段位被虐了,暂时升不了段位了,每天都拿不到首胜(好烦). 趁着学校校运会,合理地给自己放了一个小长假,然后就回家了.回到家才发现当时618 ...