带你深入的理解数组和对象的解构赋值。

es6提供了一个非常好的特性,即变量的解构赋值。从而我们可以方便的从数组和对象中提取数据并将它们赋值给变量。这是非常必要的。先来看在这个新特性发布之前我们是如何从数组中提取数据的。如下:

let nums = [1,2,3,4,5];
let num1 = nums[0];
let num2 = nums[1];

console.log(num1); // logs 1
console.log(num2); // logs 2

为了从 nums 数组中提取到数据,我们多次重复着相同的代码。es6的解构赋值将会让这个操作变得非常的容易且易于理解。

数组的解构赋值

从数组中取值并按照对应位置对变量进行赋值。如下:

 let [num1,num2,num3] = [1,2,3];
 console.log({num1},{num2},{num3})

<img src="https://user-gold-cdn.xitu.io/2020/4/8/17158daa93feba26?w=697&h=65&f=jpeg&s=14786"/>

“模式匹配”赋值

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

let [num_s,nums,num_e] = [1,[2,3,4],5];
console.log(num_s) // logs 1
console.log(nums) // logs [2,3,4]
console.log(num_e) // logs 5

用逗号跳过元素

let [num1,,,num4] = [1,2,3,4];
console.log(num1) // logs 1
console.log(num4) // logs 4

let [,num2,,num4] = [1,2,3,4];
console.log(num2) // logs 2
console.log(num4) // logs 4

查看变量赋值左侧的数组。注意这里不是只有一个逗号,而是三个。逗号分隔符用于跳过数组中的值。所以如果你想要跳过数组中的一个项,只要用逗号就可以了。

数组中的其余部分的赋值

如果我们想将数组中的一些元素赋值给变量,而将数组中的其余元素存为一个数组赋值给指定的变量怎么办?在这种情况下,我们可以这样做:

let [num1,...nums] = [1,2,3,4];
console.log(num1) // logs 1
console.log(nums) // logs [2,3,4]

应用这种方式,你可以轻松的把剩余的元素赋值给一个指定的变量。

解构失败,赋值undefined

let [num1] = [];
let [num2, num3] = [1];
console.log(num1) // logs undefined
console.log(num3) // logs undefined

代码中的变量num1与变量num3 按照模式匹配原则,并没有对应的值与之匹配,故而返回undefined。而变量num2 按照模式匹配原则,被赋值为2。

函数的解构赋值

解构赋值还可以从函数返回的数组中提取数据。假设我们有一个返回数组的函数,如下例所示:

function getLists() {
    let lists = [1,2,3,4,5]
    return lists;
}
let [num1,...nums] = getLists();

console.log(num1); // logs 1
console.log(nums); // logs [2,3,4,5]

使用默认值

数组的解构赋值可以给变量设定默认值,以防万一从数组中提取的值是 undefined(防止解构失败的情况)

let [name = "暂无姓名",sex = "女"] = ["April"];

console.log(name); // "April"
console.log(sex); // "女"

代码中变量name 默认的值为 "暂无姓名" 但是按照左右模式匹配的原则,name 被赋值为 "April" ,因为变量sex并未匹配到值,所以它的值依旧是默认值"女"

注意点1:ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效。

let [num1 = 1] = [undefined];
console.log(num1) // logs 1

let [num2 = 2] = [null];
console.log(num2) // logs null

代码中,因为null不严格等于undefined,默认值就不会生效。故而输出了 null

注意点2:如果默认值是函数,这个函数就会非常的懒,即只有在用到的时候,才会执行函数。

 function getLists(){
    let lists = [1,2,3,4,5]
    return lists; 
 }
let [lists = getLists()] = [1];
console.log(lists) // logs 1
// 因为变量 lists 可以匹配到值,所以函数 getLists() 并不会执行。

 function getLists(){
    let lists = [1,2,3,4,5]
    return lists; 
 }
let [lists = getLists()] = [];
console.log(lists) // logs [1,2,3,4,5]
// 因为变量 lists 无法匹配到值,函数 getLists() 就会执行。故而返回数据 [1,2,3,4,5]

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

let [x = 1, y = x] = [];     // logs x=1; y=1
let [x = 1, y = x] = [2];    // logs x=2; y=2
let [x = 1, y = x] = [1, 2]; // logs x=1; y=2
let [x = y, y = 1] = [];     //logs 这就要报错啦,因为x用y做默认值时,y还没有声明。

交换变量

let num1 = 1;
let num2 = 2;

[num1,num2] = [num2,num1];

console.log({num1}); // logs 2
console.log({num2}); // logs 1

对象的解构赋值

为什么要用对象的解构赋值呢??

 let profiles = {
    name:'April',
    nickname:"二十七刻",
    sign:"不以物喜,不以己悲。"
 }
           
let name = profiles.name;
let nickname = profiles.nickname;
let sign = profiles.sign;

console.log({name}) // "April"
console.log({nickname})// "二十七刻"
console.log({sign}) // "不以物喜,不以己悲。"

假设我们要从对象profiles中获取数据并赋值给新变量。就得不断的重复着取值与赋值。代码冗长且不利于维护。利用对象的解构赋值,就不存在这一问题了。

同属性名赋值

对象的解构赋值变量必须与属性同名,才能取到正确的值。如下:

let profiles = {
     name:'April', 
     nickname:"二十七刻", 
     sign:"不以物喜,不以己悲。"
}
let {name,nickname,sign} = profiles;

console.log({name})    // logs "April"
console.log({nickname})// logs "二十七刻"
console.log({sign})    // logs "不以物喜,不以己悲。"

解构失败,赋值undefined

let profiles = {
    name:'April',
    nickname:"二十七刻",
    sign:"不以物喜,不以己悲。"
}
let {name,sex} = profiles;

console.log(name) // logs "April"
console.log(sex) // logs undefined

上面代码中,因为profiles对象没有 sex属性,所以变量sex取不到值,所以就赋值undefined

在赋值之前申明变量

在对象的解构赋值中,变量可以在赋值之前申明。如下:

let profiles = {
    name:'April',
    nickname:"二十七刻",
    sign:"不以物喜,不以己悲。"
}
let name,nickname,sign;
{name,nickname,sign} = profiles;

console.log(name) // logs Error : "Unexpected token ="

嘿呀~报错了!为什么???

原因:因为忘记在{}外层写()了。

注意1 :当使用没有声明的对象字面量解构赋值时,必须使用()的赋值语句。因为 JavaScript 引擎会将{name,nickname,sign}理解成一个代码块,而不是对象字面量。

注意2 :使用此语法时,上一行代码一定要以;结束掉,否则的话会被当作函数,执行上一行的代码。

就是这个奇怪的语法 :({} = '');

正确的做法如下:

let profiles = {
    name:'April',
    nickname:"二十七刻",
    sign:"不以物喜,不以己悲。"
}
let name,nickname,sign;
({name,nickname,sign} = profiles);

console.log({name},{nickname},{sign})
// logs {name: "April"} {nickname: "二十七刻"} {sign: "不以物喜,不以己悲。"}

使用新的变量名

如果我们想用新的变量名来替代对象的属性名怎么办呢?代码如下:

let profiles = {
    name:"April",
    age:"27"
}
let {name:userName,age:userAge} = profiles;

console.log(userName) // logs "April"
console.log(userAge) // logs "27"

由此可知,对象的解构赋值其实就是let {name:name,age:age} = {name:"April",age:"27"}代码的简写。也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。

上面代码中,name是匹配的模式,userName才是变量。真正被赋值的是变量userName,而不是模式name

使用默认值

对象的解构赋值可以给变量设定默认值,以防万一从对象中获取的值是 undefined(防止解构失败的情况)需要注意的是:默认值生效的条件是,对象的属性值严格等于undefined

let staff = {name: "April", country: "China", job: "Developer"};
let {name = "暂无姓名", age = "暂无年龄"} = staff;

console.log({name}); // logs "April"
console.log({age}); // logs "暂无年龄"

代码中变量name的默认值为“暂无姓名”,但是对象staff中有属性为name的字段,所以就被赋值April,而对象staff中并没有age这个属性,所以被赋值为"暂无年龄",取了它自己的默认值。

计算属性名称

计算属性名是另一个对象特性,也适用于对象的解构赋值。你可以通过一个表达式指定一个属性的名称,把它放在[]中,如下:

let staff = {name: "April", country: "China", job: "Developer"};
let prop = "name";
let {[prop]: name} = staff;

console.log({name}); // logs "April"

对象中的其余部分的赋值

解构运算也可以被应运到解构赋值当中,来获取那些还没有被赋值的键值对,这些键值对都被放在一个新的对象里。如下:

let staff = {name: "April", country: "China", job: "Developer",nickname:"二十七刻"};
let {country,...infos} = staff;

console.log(country) //logs "China"
console.log(infos) // logs {name: "April", job: "Developer", nickname: "二十七刻"}

嵌套对象的解构赋值

let staffs = {
    group1:[ { id:"007", name:"April"}]
}
let {group1,group1:[{id,name}]} = staffs;

console.log(group1) // logs [{ id:"007", name:"April"}]
console.log(id) // logs "007"
console.log(name) // logs "April"

注意,代码中group1是模式,不是变量。如果想把group1也作为变量赋值,就要先进行定义再去赋值。

总结

数组和对象的解构赋值,本文就总结这么多。不足之处,万望指出。

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

推荐阅读更多精彩内容

  • 前面的话 我们经常定义许多对象和数组,然后有组织地从中提取相关的信息片段。在ES6中添加了可以简化这种任务的新特性...
    sunnyghx阅读 747评论 0 0
  • 前面的话   我们经常定义许多对象和数组,然后有组织地从中提取相关的信息片段。在ES6中添加了可以简化这种任务的新...
    CodeMT阅读 511评论 0 0
  • 引入 在ES5中,开发者们为了从对象和数组中获取特定数据并赋值给变量,编写了许多看起来同质化的代码 这段代码从op...
    nengzhuan_zhang阅读 621评论 0 0
  • 基本用法 ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring...
    嘉奇呦_nice阅读 788评论 0 2
  • 1.数组的解构赋值 2.对象的解构赋值 3.字符串的解构赋值 4.数值和布尔值的解构赋值 5.函数参数的解构赋值 ...
    卞卞村长L阅读 914评论 0 0