首页 web前端 js教程 详解ECMAScript6变量的解构赋值

详解ECMAScript6变量的解构赋值

Feb 08, 2018 pm 01:07 PM
赋值

ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring),本文主要和大家分享嵌套数组的解构例子,大家一起看看吧var [a, b, c] = [1, 2, 3];

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

下面是一些使用嵌套数组进行解构的例子

let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3
let [ , , third] = ["foo", "bar", "baz"];
third // "baz"
let [x, , y] = [1, 2, 3];
x // 1
y // 3
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
登录后复制

如果解构不成功,变量的值就等于 undefined

foo 的值都会等于 undefined

var [foo] = [];
var [bar, foo] = [1];
登录后复制

不完全解构即等号左边的模式,只匹配一部分的等号右边的数组

let [x, y] = [1, 2, 3];
x // 1
y // 2
let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
登录后复制

如果等号的右边不是数组,那么将会报错。

// 报错let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
登录后复制

解构赋值不仅适用于var命令,也适用于let和const命令

var [v1, v2, ..., vN ] = array;
let [v1, v2, ..., vN ] = array;
const [v1, v2, ..., vN ] = array;
登录后复制

对于Set结构,也可以使用数组的解构赋值。

let [x, y, z] = new Set(["a", "b", "c"]);
x // "a"
登录后复制

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

function* fibs() {
  var a = 0;
  var b = 1;
  while (true) {
  yield a;
   [a, b] = [b, a + b];
  }
}
var [first, second, third, fourth, fifth, sixth] = fibs();
sixth // 5
登录后复制

fibs 是一个Generator函数,原生具有Iterator接口。解构赋值会依次从这个接口获取值

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

var [foo = true] = [];
foo // true
[x, y = 'b'] = ['a']; // x='a', y='b'
[x, y = 'b'] = ['a', undefined]; // x='a', y='b'
登录后复制

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

var [x = 1] = [undefined];
x // 1
var [x = 1] = [null];
x // null
登录后复制

如果一个数组成员是 null ,默认值就不会生效,因为 null 不严格等于 undefined

function f() {
console.log('aaa');
}
let [x = f()] = [1];
//等价于
let x;
if ([1][0] === undefined) {
  x = f();
} else {
  x = [1][0];
}
登录后复制

如果默认值是一个表达式,那么这个表达式是惰性求值的,即只有在用到的时候,才会求值

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

let [x = 1, y = x] = []; // x=1; y=1
let [x = 1, y = x] = [2]; // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = []; // ReferenceError
登录后复制

是因为 x 用到默认值 y 时, y 还没有声明

对象的解构赋值

var { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
登录后复制

数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值

var { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
var { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined
登录后复制

实际上,对象的解构赋值是下面形式的简写

var { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };
登录后复制

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

var { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
foo // error: foo is not defined
登录后复制

上面代码中,真正被赋值的是变量 baz ,而不是模式 foo

变量的声明和赋值是一体的。对于let和const来说,变量不能重新声明,所以一旦赋值的变量以前声明
过,就会报错

let foo;
let {foo} = {foo: 1}; 
// SyntaxError: Duplicate declaration "foo"
let baz;
let {bar: baz} = {bar: 1}; 
// SyntaxError: Duplicate declaration "baz"
登录后复制

因为 var 命令允许重新声明,所以这个错误只会在使用 let 和 const 命令时出现。如果没有第二个let命令,上面的代码就不会报错

let foo;
({foo} = {foo: 1}); // 成功
let baz;
({bar: baz} = {bar: 1}); // 成功
登录后复制

和数组一样,解构也可以用于嵌套结构的对象

var obj = {
  p: [
   "Hello",
   { y: "World" }
  ]
};
var { p: [x, { y }] } = obj;
x // "Hello"
y // "World"
登录后复制

这时 p 是模式,不是变量,因此不会被赋值

var node = {
  loc: {
   start: {
     line: 1,
     column: 5
   }
  }
};
var { loc: { start: { line }} } = node;
line // 1
loc // error: loc is undefined
start // error: start is undefined
登录后复制

只有 line 是变量, loc 和 start 都是模式,不会被赋值

嵌套赋值的例子。

let obj = {};
let arr = [];
({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });
obj // {prop:123}
arr // [true]
登录后复制

对象的解构也指定默认值

var {x = 3} = {};
x // 3
var {x, y = 5} = {x: 1};
x // 1
y // 5
var { message: msg = "Something went wrong" } = {};
msg // "Something went wrong"
登录后复制

默认值生效的条件是,对象的属性值严格等于 undefined

var {x = 3} = {x: undefined};
x // 3
var {x = 3} = {x: null};
x // null
登录后复制

如果解构失败,变量的值等于 undefined

var {foo} = {bar: 'baz'};
foo // undefined
登录后复制

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

// 报错
var {foo: {bar}} = {baz: 'baz'};
登录后复制

等号左边对象的 foo 属性,对应一个子对象。该子对象的 bar 属性,解构时会报错。因为 foo 这时等于 undefined ,再取子属性就会报错

要将一个已经声明的变量用于解构赋值,必须非常小心

// 错误的写法
var x;
{x} = {x: 1};
// SyntaxError: syntax error
// 正确的写法
({x} = {x: 1});
登录后复制

因为JavaScript引擎会将 {x} 理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免JavaScript将其解释为代码块,才能解决这个问题

对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量

let { log, sin, cos } = Math;
登录后复制

将 Math 对象的对数、正弦、余弦三个方法,赋值到对应的变量上,使用起来就会方便很多

字符串的解构赋值

字符串也可以解构赋值。此时字符串被转换成了一个类似数组的对象

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
登录后复制

类似数组的对象都有一个 length 属性,因此还可以对这个属性解构赋值

let {length : len} = 'hello';
len // 5
登录后复制

数值和布尔值的解构赋值

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

let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
登录后复制

数值和布尔值的包装对象都有 toString 属性,因此变量 s 都能取到值

解构赋值的规则是,只要等号右边的值不是对象,就先将其转为对象。由于 undefined 和 null 无法转为对象,所以对它们进行解构赋值,都会报错。

let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
登录后复制

函数参数的解构赋值

function add([x, y]){
  return x + y;
}
add([1, 2]); // 3
登录后复制

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

function move({x = 0, y = 0} = {}) {
  return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]
登录后复制

函数 move 的参数是一个对象,通过对这个对象进行解构,得到变量 x 和 y 的值。如果解构失败, x 和 y 等于默认值

function move({x, y} = { x: 0, y: 0 }) {
return [x, y];
}
move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]
登录后复制

是为函数 move 的参数指定默认值,而不是为变量 x 和 y 指定默认值,所以会得到与前一种写法不同的结果。undefined 就会触发函数参数的默认值

圆括号问题

解构赋值虽然很方便,但是解析起来并不容易。对于编译器来说,一个式子到底是模式,还是表达式,没有办法从一开始就知道,必须解析到(或解析不到)等号才能知道如果模式中出现圆括号怎么处理。ES6的规则是,只要有可能导致解构的歧义,就不得使用圆括号。但是,这条规则实际上不那么容易辨别,处理起来相当麻烦。因此,建议只要有可能,就不要在模式中放置圆括号

不能使用圆括号的情况

1.变量声明语句中,不能带有圆括号

// 全部报错
var [(a)] = [1];
var {x: (c)} = {};
var ({x: c}) = {};
var {(x: c)} = {};
var {(x): c} = {};}
var { o: ({ p: p }) } = { o: { p: 2 } };
登录后复制

2.函数参数中不能使用圆括号

// 报错
function f([(z)]) { return z; }
登录后复制

3.赋值语句中,不能将整个模式,或嵌

套模式中的一层,放在圆括号之中

将整个模式放在模式之中,导致报错

// 全部报错
({ p: a }) = { p: 42 };
([a]) = [5];
登录后复制

将嵌套模式的一层,放在圆括号之中,导致报错

[({ p: a }), { x: c }] = [{}, {}];
登录后复制

可以使用圆括号的况

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

[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确
登录后复制

首先它们都是赋值语句,而不是声明语句;其次它们的圆括号都不属于模式的一部分。第一行语句中,模式是取数组的第一个成员,跟圆括号无关;第二行语句中,模式是p,而不是d;第三行语句与第一行语句的性
质一致

用途

1.交换变量的值

[x, y] = [y, x];
登录后复制

2.从函数返回多个值

// 返回一个数组
function example() {
  return [1, 2, 3];
}
var [a, b, c] = example();
// 返回一个对象
function example() {
  return {
   foo: 1,
   bar: 2
  };
}
var { foo, bar } = example();
登录后复制

3.函数参数的定义

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

function f([x, y, z]) { ... }
f([1, 2, 3]);
// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});
登录后复制

4.提取JSON数据

var jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]
登录后复制

5.函数参数的默认值

jQuery.ajax = function (url, {
  async = true,
  beforeSend = function () {},
  cache = true,
  complete = function () {},
  crossDomain = false,
  global = true,
  // ... more config
}) {
  // ... do stuff
};
登录后复制

6.便利Map结构

var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
  console.log(key + " is " + value);
}
// first is hello
// second is world
// 获取键名
for (let [key] of map) {
// ...
}
// 获取键值
for (let [,value] of map) {
// ...
}
登录后复制

7.输入模块的指定方法

const { SourceMapConsumer, SourceNode } = require("source-map")
登录后复制

相关推荐:

ECMAScript6是什么?

ECMAScript6入门之Class对象的实例详解

ECMAScript6新增值比较函数Object.is_javascript技巧

以上是详解ECMAScript6变量的解构赋值的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

如何为VMware虚拟机启用复制和粘贴 如何为VMware虚拟机启用复制和粘贴 Feb 21, 2024 am 10:09 AM

您可以轻松地在VMware虚拟机(VM)和物理系统之间复制和粘贴文本和文件。这种功能让您可以方便地在虚拟机和主机系统之间传输图像、格式化和非格式化文本,甚至电子邮件附件。本文将向您展示如何启用这一功能,并演示复制数据、文件和文件夹的方法。如何在VMware中启用复制/粘贴VMware提供了三种不同的方式将数据、文件或文件夹从虚拟机复制到物理计算机,反之亦然,如下所述:复制和粘贴要素拖放功能文件夹共享1]使用VMware工具启用复制粘贴如果您的VMWare安装和来宾操作系统满足要求,则可以使用键盘

如何在Word中复制页面 如何在Word中复制页面 Feb 20, 2024 am 10:09 AM

是否要复制MicrosoftWord中的页面,并保持格式不变?这是一个聪明的想法,因为当您想要创建特定文档布局或格式的多个副本时,在Word中复制页面可能是一种有用的节省时间的技术。本指南将逐步引导您在Word中复制页面的过程,无论是创建模板还是复制文档中的特定页面。这些简单的说明旨在帮助您轻松地重新制作页面,省去从头开始的麻烦。为什么要在MicrosoftWord中复制页面?在Word中复制页面非常有益的原因有以下几点:当您有一个具有特定布局或格式的文档要复制时。与从头开始重新创建整个页面不同

解锁 macOS 剪贴板历史记录,高效复制、粘贴技巧 解锁 macOS 剪贴板历史记录,高效复制、粘贴技巧 Feb 19, 2024 pm 01:18 PM

在Mac上,经常需要在不同文档之间复制和粘贴内容是常见的。macOS的剪贴板只保留最后一个复制项,这限制了我们的工作效率。幸运的是,有一些第三方应用程序可以帮助我们轻松查看和管理剪贴板的历史记录。如何在「访达」中查看剪贴板内容「访达」中内置了一个剪贴板查看器,让你可以随时查看当前剪贴板中的内容,以免错误粘贴。操作非常简单:打开「访达」,点击「编辑」菜单,然后选择「显示剪贴板」。在「访达」中查看剪贴板内容这个功能虽小,却有几点需要注意:「访达」中的剪贴板查看器只能显示内容,无法编辑。如果你复制的是

在终端中禁用或启用自动复制所选内容以进行复制 在终端中禁用或启用自动复制所选内容以进行复制 Mar 24, 2024 am 09:46 AM

本文将向您介绍如何在Windows终端中启用或禁用自动将选择内容复制到剪贴板的功能。Windows终端是微软专为Windows11/10开发的多标签终端模拟器,取代了传统的命令提示符。它支持运行命令提示符、PowerShell、WSL、Azure等应用程序。通常在终端工作时,用户需要复制命令和输出,然而终端默认情况下不支持复制选择操作。请继续阅读本文,了解如何解决这个问题。如何在终端中启用或禁用自动复制所选内容到缓存?以下是您如何启用或禁用自动复制选择到终端剪贴板:打开终端应用程序,然后点击上面

学习Golang中的变量定义和赋值 学习Golang中的变量定义和赋值 Jan 18, 2024 am 10:00 AM

Golang中变量的定义与赋值,需要具体代码示例在Golang中,变量的定义和赋值是非常简单和直观的。本文将通过具体的代码示例来介绍Golang中变量的定义和赋值。首先,我们来看看Golang中变量的定义。在Golang中,变量的定义可以使用var关键字来完成。具体的语法如下所示:var变量名类型其中,var表示变量的定义关键字,变量名为你自己定义的变量

php中赋值方式有哪些 php中赋值方式有哪些 Jul 26, 2023 pm 01:11 PM

php中赋值方式有:1、直接赋值,使用"="操作符直接为变量赋值;2、引用赋值,使用"=&"操作符,将一个变量的引用赋给另一个变量;3、动态赋值,通过变量名的字符串形式,使用可变变量进行赋值;4、数组赋值,将一个数组赋给另一个变量;5、列表赋值,将一个数组的值赋给一组变量,一次可以赋多个值;6、对象赋值,将一个对象赋给一个变量;7、使用赋值运算符的扩展形式,如+=、-=等。

技巧和注意事项:不同的字符串数组赋值方法 技巧和注意事项:不同的字符串数组赋值方法 Dec 26, 2023 am 11:30 AM

使用不同方式给字符串数组赋值的技巧与注意事项简介:在编程中,经常需要使用数组来存储一组相关数据。尤其是在处理字符串时,经常需要使用字符串数组来存储多个字符串。本文将介绍一些常用的方法,给字符串数组赋值的技巧和注意事项,并提供代码示例。直接赋值直接赋值是最简单的一种方式,可以在声明字符串数组的同时,直接给数组元素赋值。示例代码如下:String[]fruit

Go 语言中的变量赋值有哪些方式? Go 语言中的变量赋值有哪些方式? Jun 11, 2023 pm 01:22 PM

Go语言是一门静态类型的编程语言,由Google开发,于2009年正式发布。它的风格简洁,语法规范,对于并发编程提供了很好的支持。Go语言中变量的赋值方式也是其特色之一。本文将介绍几种常见的变量赋值方式。一、直接赋值Go语言中最基本的变量赋值方式是直接将变量赋值给一个值或表达式。例如:varainta=10以上代码将整数10赋值给

See all articles