变量的解构赋值

ES6允许按照一定的模式从数组或者对象中提取值,然后对变量进行赋值,这种方式成为解构赋值,这使得在平时的编程中变得高效简洁,解构赋值有以下内容:

数组的解构赋值

1、基本用法

//es6以前
var a = 1;
var b = 2;
var c = 3;
// es6
let [a,b,c] = [1,2,3]
//可得到
a // 1
b // 2
c // 3

由以上的赋值是从数组中提取值,然后【按照对应位置对变量进行赋值】
其本质上属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
如下例子:

let [foo,[[bar],baz]] = [1,[[2],3]];
foo // 1
bar // 2
baz //3
//即以上的的等号两边的模式相同,可以进行对应位置变量的赋值
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] = [1]
x // 1
y // undefined
z // undefined
// 这种情况属于解构不成功,所以未解构到的变量会等于undfined
let [x,y] = [1,2,3]
x // 1
y // 2
//这种情况属于不完全解构,即等号左边的模式只匹配一部分的等号右边的数组,但这种情况依然是解构成功
但是,如果等号的右边不是数组(严格来说不是可遍历的结构),那么将会报错
let [a] = 1;
let [b] = false;
let [c] = NaN;
let [d] = undefined;
let [e] = null;
let [f] = {};
//以上语句都会报错,因为等号右边的值或者是转为对象以后不具备Iterator接口(前5个表达式)
//或者本身不具备Iterator接口(最后一个表达式)

2、默认值

解构赋值允许制定默认值,即es6内部会严格使用相等运算符(===)判断一个位置是否有真值,所以如果一个数组成员不严格等于undefined,默认值是不会生效的,反之,默认值生效。

let [x = 1] = [undefined];
x // 1

let [ y = 2] = [];
y // 2

let [z = 3] = [null];
z // null
// 此时因为null不严格等于undefined
// 如果默认值是一个表达式,那么这个表达式是惰性求值,即只有在用到时才会求值
function f() {
    console.log(111);
}
let [x = f()] = [1];//此时,因为x能够取到值1,所以函数f根部不会执行


以上的解构赋值代码等价于于:
let x;
if([1][0] === undefined) {
    x = f();
}else{
    x = [1][0];
}
//默认值也可以引用解构赋值的其他变量,但必须保证在引用前,该变量以声明
let [x = 1,y = 2] = []; // x=1,y=2
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还没有声明

2、对象的解构赋值

对象的解构赋值与数组有一个重要的区别,即数组的元素时按次序排列的,变量的取值是由它的位置决定的;而对象的属性没有次序,变量必须与属性同名才能取到正确的值。
对象的解构赋值的内部机制是先找到同名属性,然后再复制给对应的变量,真正被赋值的是后者而不是前者,见如下栗子:

let {bar,foo} = {foo:1,bar:2};
foo // 1
bar // 2

//以上赋值等价于下面代码,即当变量名与属性名相同时,可简写
let {bar:bar,foo:foo} = {foo:1,bar:2};
foo //1
bar // 2

//如果变量名与属性名不一样时,需要写全:
let {foo:baz} = {foo:3,bar: 4};
baz // 3
foo // error: foo is not defined
// 上面代码中,foo时匹配的模式,baz才是变量,真正被复制的是变量baz,而不是模式foo
//解构同样也可以用于嵌套结构的对象
let = {
    p: [
        'hello',
        {y: 'world'}
    ]
};
let {p:[x,{y}]} = obj;
x // hello
y // world
//在此处,p是模式不是变量,因此不会被赋值
对象的解构也可以指定默认值

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

let {x = 3} = {};
x // 3

let {x,y=5} = {x :1};
x // 1
y // 5

let {x:y = 5} = {};
y //5

let {x:y=5} = {x:3};
y // 3

let {x = 3} = {x:null};
x // null
注意:如果要将一个已经声明的变量用于解构赋值,必须非常小心
let x;
{x} = {x:1}; //SyntaxError: syntax error
//以上的代码报错,是因为javascript引擎会将{x}理解成一个代码块,从而发生了语法错误
//只有不将大括号写在行首,避免javascript将其解释为代码块,才能解决这个问题

//正确写法
let x;
({x}) = {x:1};
x // 1

3、字符串的解构赋值

字符串也可以解构赋值,因为吃屎字符串被转换成了一个类似数组的对象

let [a,b,c] = 'god';
a // g
b // o
c // d
//类数组的对象都有一个属性length,因此还可以对这个属性进行解构赋值
let {length:len} = 'hello';
len // 5

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

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

let {toString:s} = 123;
s === Number.prototype.toString   // true
//数值的包装对象都有toString属性,因此变量s都能取到值。

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

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

5、函数参数的解构赋值

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

// 函数add的参数表面上是一个数组,但在传入参数的那一刻,数组参数就被解构成x和y;
//所以对于函数内部的代码来说,它们能感受到的参数就是x和y。
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]
注意,一下写法则会得到不一样的结果
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指定默认值,所以会的得到不一样的结果。

6、圆括号问题

解构赋值虽然方便,但解析起来并不容易,对于编译器来说,一个式子到底是模式还是表达式,没有办法一开始就知道,必须解析到(或解析不到)等号才能知道。
由此带来的问题是,如果模式中出现圆括号该怎么处理?ES6的规则是:之哟啊有可能导致结构有歧义,就不得使用圆括号。

不能使用圆括号的情况

1、变量声明语句

// 一下全部报错
let [(a)] = [1];
let {x:(c)} = {};
let {(x:c)} = {};
let ({x:c}) = {};
let {(x):c} = {};
let {o: ({p:p})} = {o:{p:2}};
//上面6个语句都会报错,因为他们都是变量声明语句,模式不能使用圆括号。

2、函数参数
函数参数也属于变量声明,因此不能使用圆括号

function f([(a)]) {return a}
function f([z,(x)]) {return x}
// 以上都会报错

3、赋值语句的模式

({p:a}) = {p:1}
([a]) = [5];
// 以上都会报错
可以使用圆括号的情况

可以使用圆括号的情况只有一种:赋值语句的飞魔士部分可以使用圆括号

// 以下使用正确
[(b)] = [3];
({p:(d)} = {p:3});
//以上语句都可以正确执行,因为都是赋值语句而不是声明语句。

7、变量解构赋值的用途

主要可以适用在以下几种情况:
1、交换变量

let x = 1;
let y = 2;
[x,y] = [y,x];

2、从函数返回多个值

function f(){
     return [1,2,3];
}
let [a,b,c] = f();

3、函数参数的定义
4.提取JSON数据
5、函数参数的默认值
6、遍历Map解构
7、输入模块的制定方法

const {a,b} = require('xxx.js')
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,825评论 4 377
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,887评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,425评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,801评论 0 224
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,252评论 3 299
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,089评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,216评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 31,005评论 0 215
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,747评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,883评论 2 255
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,354评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,694评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,406评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,222评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,242评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,017评论 2 281

推荐阅读更多精彩内容

  • 1.数组的解构赋值 2.对象的解构赋值 3.字符串的解构赋值 4.数值和布尔值的解构赋值 5.函数参数的解构赋值 ...
    卞卞村长L阅读 911评论 0 0
  • 数组的解构赋值 基本用法 ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destru...
    呼呼哥阅读 422评论 0 3
  • 本文通过学习阮一峰的博客,外加自己的理解,整理了一下我对js变量的解构赋值的理解。 数组的解构赋值 对象的解构赋值...
    宋乐怡阅读 428评论 0 2
  • 1.数组的解构赋值 基本用法 ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Des...
    angelwgh阅读 493评论 0 0
  • 01、数组的解构赋值ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destruct...
    夜幕小草阅读 297评论 0 1