ES6学习-解构

对象和数组字面量是JavaScript中两种最常用的数据结构,由于JSON数据结构的普及,两者已经成为语言中特别重要的一部分。在编码过程中,我们经常定义许多对象和数组,然后有组织地从中提取相关的信息片段。ES6添加了可以简化这种任务的新特性:解构。

为何使用解构功能

在ES5中,开发者为了从对象和数组中获取特定数据并赋值给变量,编写了很多同质化代码。

let options={
    repeat: true,
    save: false
};
//从对象中提取数据
let repeat=options.repeat,
    save=options.save;

这段代码中从options中提取repeat和save的值并存储的过程十分相似,如果需要得到的值很多,则会编写很多次同质化代码,如果代码中海油嵌套结构,则会非常麻烦。
所以ES6为对象和数组都添加了结构功能,将数据结构打散过称变得很简单,使我们更容易获取信息。

对象解构

对象字面量的语法形式是在一个赋值操作符左边放置一个对象字面量。

let node={
    type:"Indetifier",
    name:"foo"
};
let {type,name}=node;
console.log(type);//"Indetifier"
console.log(name);//"foo"

在这段代码中,node.type的值存储在名为type的变量中;node.name的值存储在名为name的变量中。
值得注意的是:如果用var、let和const解构声明变量,则必须要为其初始化,否则报错。

//语法错误
var {type,name};
//语法错误
let {type,name};
//语法错误
const {type,name};
解构赋值

我们同样可以在给变量赋值时使用解构语法。

let node={
    type:"Indetifier",
    name:"foo"
},
    type="Literal",
    name=5;
({type,name}=node);
console.log(type);//"Indetifier"
console.log(name);//"foo"

在示例中,声明type和name时初始化了一个值,在后面通过结构重新赋值。需要注意的地方是:因为开放的{}会被视为代码块,而语法规定,代码块不允许出现在赋值语句左边,所以需要加小括号使其转化为一个表达式。
结构表达式的值与表达式右侧(也就是=右侧)的值相等,如此在任何可以使用值得地方你都可以使用解构赋值表达式。

let node={
    type:"Indetifier",
    name:"foo"
},
    type="Literal",
    name=5;
function outputInfo(value){
    console.log(value==node);//true
}
console.log(type);//"Indetifier"
console.log(name);//"foo"

值得注意的点是:如果右侧的值为null或undefined会导致程序抛出错误。也就是尝试读取null和undefined的属性的行为都会抛出错误。

默认值

如果指定的局部变量名称在对象中不存在,那么这个局部变量会被赋值undefined。

let node={
    type:"Indetifier",
    name:"foo"
};
let {type,name,value}=node;
console.log(type);//"Indetifier"
console.log(name);//"foo"
console.log(value);//"undefiined"

当指定属性不存在时,可以随意定义一个默认值。

let node={
    type:"Indetifier",
    name:"foo"
};
let {type,name,value=true}=node;
console.log(type);//"Indetifier"
console.log(name);//"foo"
console.log(value);//"true"
为非同名局部变量赋值

如果希望用不同命名的局部变量来存储对象属性的值,可以这样写。

let node={
    type: "Identifier",
    name: "foo"
};
let {type: localType,name: localName}=node;
console.log(localType);//"Identifier"
console.log(localName);//"foo"

这段代码使用了解构声明来声明变量localType和localName,这两个量分别包含node.type和node.name的值,
当使用其他变量名进行赋值时也可以为其添加默认值。

let node={
    type: "Identifier",
};
let {type: localType="hahaha",name: localName="ccg"}=node;
console.log(localType);//"Identifier"
console.log(localName);//ccg
嵌套对象解构
let node={
    type: "Identifier",
    name: "foo",
    loc: {
        start: {
            line: 1,
            column: 1
        },
        end: {
            line: 1,
            column: 4
        }
    }
};
let {loc:{start}}=node;
console.log(start.line);//1
console.log(start.column);//1

在这个示例中,我们在解构模式中使用了花括号,其含义是在找到node对象的loc属性后,深入一层找到start属性。
更近一步,可以使用一个与对象属性名不同的局部变量名:

let node={
    type: "Identifier",
    name: "foo",
    loc: {
        start: {
            line: 1,
            column: 1
        },
        end: {
            line: 1,
            column: 4
        }
    }
};
let {loc:{start: localStart}}=node;
console.log(localStart.line);//1
console.log(localStart.column);//1

对象解构功能很好用,但是值得注意的是,你可能会创建一个无效表达式,它是合法的,但是什么都干不了。

//未申明任何变量
let {loc:{}}=node;

左边的loc不是即将创建的绑定,只是代表对象中的检索属性的位置。

数组解构

与对象解构的语法相比,数组解构就简单多了,它使用的是数组字面量,且解构操作全部在数组内完成,而不是像对象字面量语法一样使用对象的命名属性:

let colors=["red","green","blue"];
let [firstColor,secondColor]=colors;
console.log(firstColor);//"red"
console.log(secondColor);//"green"

在这段代码中,我们从colors数组中解构出“red”和“green”这两个值,并分别存储在变量firstColor和变量secondColor中。在数组解构语法中,我们通过值在数组的位置进行选取,且可以将其存储在任意变量中,未显式申明的元素会被忽略哦。值得注意的是,这个过程中数组不会发生任何变化。
在解构模式中,也可以直接省略元素,只为需要的元素提供变量名。

let colors=["red","green","blue"];
let [ , , thirdColor]=colors;
console.log(thirdColor);//"blue"

thiirdColor前的逗号是前方元素的占位符,无论数组元素有多少个,你都可以通过这种方式提取需要的元素,并不需要额外指定变量名。
值得注意的是:使用var、let和const声明数组解构的绑定时,必须要提供一个初始化程序。

解构赋值

数组解构也可以用于赋值上下文,但不需要用小括号包裹表达式,这一点与数组解构的约定不同。

let colors=["red","green","blue"],
     firstColor="black",
     secondColor="purple";
[firstColor,secondColor]=colors;
console.log(firstColor);//"red"
console.log(secondColor);//"green"

解构语法中还有一个特例:交换两个变量的值。

//在es5中交换变量
let a=1,
     b=2,
     tmp;
tmp=a;
a=b;
b=tmp;
console.log(a);//2
console.log(b);//1
//如果使用数组解构赋值语法,就不需要用额外的变量了。
//在ES6中交换变量
let a=1,
     b=2;
[a,b]=[b,a];
console.log(a);//2
console.log(b);//1

代码执行过程中:先解构临时数组,将b和a的值复制到左侧数组的前两个位置,最终结果是变量互换了它们的值。
值得注意的是:如果右侧数组解构赋值表达式的值为null或undefined,则会导致程序 抛出错误。

默认值

也可以在数组解构赋值表达式中为数组中的任意位置添加默认值,当指定位置的属性不存在或其值为undefined时使用默认值:

let colors=["red"];
let [firstColor,secondColor="green"]=colors;
console.log(firstColor);//"red"
console.log(secondColor);//"green"
嵌套数组解构

在原有的数组模式中插入另一个数组模式,即可将解构过程深入到下一层次:

let colors=["red",["green","lightgreen"],"blue"];
//接下来
let [firstColor,[secondColor]]=colors;
console.log(firstColor);//"red"
console.log(secondColor);//"green"
不定元素

数组解构中也可以用不定元素。

let colors=["red","green","blue"];
let [firstColor,...restColors]=colors;
console.log(firstColor);//"red"
console.log(restColors.length);//2
console.log(restColors[0]);//"green"
console,log(restColors[1]);//"blue"
数组复制
//在ES5中克隆数组
var colors=["red","green","blue"];
var clonedColors=colors.concat();//concat()设计初衷是用于连接两个数组,当不传递 参数时就会返回当前的副本。
console.log(clonedColors);//
//在ES6中的新方法
let colors=["red","green","blue"];
let [...clonedColors]=colors;
console.log(clonedColors);//"[red,green,blue]"

比较这个方法和concat()方法的可读性,喜欢用哪个你就用哪个吧。QAQ...
值得注意的是在被解构的数组中,不定元素必须为最后一个条目,在后面添加逗号会报错。

混合解构

可以混合使用对象解构和数组解构来创建更多复杂的表达式。

let node={
    type:"Indentifier",
    name:"foo",
    loc:{
        start:{
            line:1,
            column:1
        },
        end:{
            line:1,
            column:4
        }
    },
    range:[0,3]
};
let {
    loc:{start},
    range:[startIndex]
}=node;
console.log(start.line);//1
console.log(start.column);//1
console.log(startIndex);//0
解构参数

解构可以用在函数参数的传递过程中,这种特别方式更特别。当定义接受大量可选参数的JavaScript函数时,我们通常会创建一个可选对象,将额外的参数定义为这个对象的属性。

//options的属性表示其他参数
function setCookie(name,value,options){
    options=options||{};
    let secrue=options.secrue,
        path=options.path,
        domain=options.domain,
        expires=options.expires;
    //设置cookie的代码
}
//第三个参数映射到options中
setCookie("type","js",{
    secrue:true,
    expires:60000
});

这样的setCookie存在的问题是仅查看函数的声明部分,无法辨识函数的预期函数,必须阅读函数体才可以确定所有参数的情况。
定义为解构函数就可以解决这个问题。

function setCookie(name,value,{secrue,path,domain,expires}){
    //设置cookie的代码
}
//第三个参数映射到options中
setCookie("type","js",{
    secrue:true,
    expires:60000
});
必须传值的解构参数

解构函数有个奇怪的地方,默认情况下,如果调用函数时不提供被解构的参数会导致程序抛出错误。

setCookie("type","js");//程序报错

缺失的第三个参数,其值为undefined,而解构参数只是将解构声明应用到在函数参数的一个写法,其会导致程序抛出错误。当调用setCookie()函数时,JavaScript引擎实际上做了这些事情:

function setCookie(name,value,options){
    let {secure,path,domain,expires}=options;
   //设置cookie的代码
}

如果解构表达式的右边为null或undefined,则程序会报错,同理,调用时不传参数也会报错。
如果希望解构函数参数可选,可以这样写:

function setCookie(name,value,{secure,path,domain,expires}={}){
   //...
}
解构参数的默认值

可以为解构函数指定默认参数值,就像在解构赋值语句中一样,只需要添加默认值就好了。

function setCookie(name,value,{
    secure=false,
    path="/",
    domain="example.com",
    expires=new Date(Date.now()+360000000)
}){
    //...
}

这种方法看着挺清晰,但是函数声明比以前复杂,这里建议直接用相同的解构作为默认参数:

function setCookie(name,value,{
    secure=false,
    path="/",
    domain="example.com",
    expires=new Date(Date.now()+360000000)
}={
    secure=false,
    path="/",
    domain="example.com",
    expires=new Date(Date.now()+360000000)
}
){
    //...
}

现在函数变得更加完整了,第一个对象字面量是解构参数,第二个为默认值,为了解决部分代码冗余,可以将默认值封装在一个独立对象中。

const setCookDefaults={
    secure=false,
    path="/",
    domain="example.com",
    expires=new Date(Date.now()+360000000)
};
function setCookie(name,value,{
    secure=false,
    path="/",
    domain="example.com",
    expires=new Date(Date.now()+360000000)
}=setCookieDefaults
){
    //...
}

在这段代码中,默认值已经被放到setCookieDefaults对象中,除了作为默认参数值,在解构参数中可以直接使用这个对象为每一个绑定设置默认值。使用解构参数后,不得不处理默认参数的复杂逻辑,但它也有好的一面,如果要改变默认值,可以立即在setCookieDefaults中修改,改变的值将自动同步到所有出现过的地方。

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

推荐阅读更多精彩内容