Table of Content

对象和数组的字面量是我们最常用的两种方式,已经是我们这门语言很重要的组成部分.在写代码的时候,基本上任何时候都会在定义对象和数组.定义之后再从这些结构中取出数据.

ES6增加了解构功能.是一个把数组结构分解到更小更精更细的部分的过程 .今天的课程以此展开.

5.1 解构有什么用

在ES6之前,从对象或是数组中获取数据,或是信息.需要写很多相似的代码

比如:

let options = {
    x:true,
    y:false
}

let x = options.x,
    y = options.y;

以上的代码显示了从对象中取出数据,赋值给了同名的本地变量上.如果只有这样两个.其实也还好.但是如果想象一下有100个.我们是不是需要一个个拿出来赋值,并且如果有一个嵌套的数据结构还要遍历寻找信息,在这种情况下.可能我们只是想要拿出其中一个小节的数据.去深挖整个数据结构。

基于这种情况。ES6增加了个解构赋值的功能。

5.2 对象解构

对象解构在赋值语法的左侧用了对象字面量,比如:

let user = {
    name:"赵中",
    age:20
}

let {name,age} = user;

console.log(name)
console.log(age)

以上代码中.user.name的值被赋值给了本地的变量 name ,user.age给了本地变量age.以上这种写法,属于简写的属性初始化器.name,age标识符代表了本地变量.也读取了相应的属性值

当使用解构来配合var,let,const 来声明变量时.必须提供初始化(也就是等号右边的值) 比如:

var {name,age};       //语法错误
let {name,age};       //语法错误
const {name,age}      //语法错误

const 本身的要求就是必须要有初始化.就算是没有使用解构,也是必须要有初始化的值,

let,var则仅仅在使用解构的时候才有此要求;

5.2.1 解构赋值

以上案例用于变量声明,但是,也可以在赋值的时候使用解构.比如,我想在变量声明之后改变它们的值:比如

let user = {
    name:"赵中",
    age:20
};
let name = '颜色';
let age = 22;

// 使用解构来分配不同的值
({name,age} = user)

console.log(name)
console.log(age)

在以上这个案例中,name和age属性在声明时被初始化,而同时有两个同名变量也被声明且初始化为不同的值,接下来有一行使用解构表达式,能过读取user对象来更改这两个 变量的值.

这里需要注意的是必须用圆括号包裹解构赋值语句,这是因为暴露的花括号会被解析为代码块语句,而块语句不允许在赋值操作符左侧出现.圆括号标示的的意思是花括不是块语句,而被解释为表达式.从而允许完成赋值操 作.

解构赋值表达式的值为右侧赋值操作符之后的值,就是说在任何期望有值的位置都可以使用解构赋值表达式.比如:

let user = {
    name:"赵中",
    age:20
};
let name = '颜色';
let age = 22;

function out(value){
   console.log(value===user); //true
}

out({name,age}=user)

console.log(name)
console.log(age)

以上这个函数在被使用一个解构赋值表达式进行了调用,这个表达式的计算结果为user,因为表达式右侧的值.对name,age的赋值正常进行.同时user也被传入out函数

在使用解构赋值表达式的时候右侧的计算结果如果是null或是undefiend,会出现错误.因为任何读取null或undefined的行为都导致运行时错误.(runtime error)

5.2.2 解构默认值

在使用解构赋值语句时,如果我们所指定的本地变量在对象中没有找到同名属性,哪么这个变量的值赋值为undefined

let user = {
    name:"赵中",
    age:20
};

let {name,age,job} = user;

console.log(name)
console.log(age)
console.log(job)

以上代码定义了一个额外变job,并且试图希望对其赋值.但是user中不存在同名属性,因此job理所当然赋值为undefined.

当然可以为他定义一个默认值,在指定属性不存在的时候使用这个默认值。如果想要实现这样的效果,比如:

 let {name,age,job = true} = user;

以上的变量job被指定了一个默认值,这个默认值只有在user对应的属性缺失的情况下,或对应的属性值为undefined的情况下。才会被启用。比如:

let user = {
    name:"赵中",
    age:20,
    job:'前端工程师'   //如果这里有值,并不为undefined 就使用这里的值,否则就用true
};

let {name,age,job = true} = user;

console.log(name)
console.log(age)
console.log(job)

5.2.3 赋值给不同的本地变量

以上的每个案例,我们都使用了对象中的属性名作为本地变量的名称,如果使用相同的名称,这样做是没有任何的问题的,但是如果你不想使用属性中的同名属性作为本地变量?

ES6有一个扩展语法。允许你在给本地变量赋值的时候使用一个不同的名称。比如:

let user = {
    name:"赵中",
    age:20,
    job:'前端工程师'
};

let {
    name:n,
    age:a,
    job:j
} = user

console.log(n)
console.log(a)
console.log(j)

在以上为个案例中,我们使用了解构赋值来声明了三个变量。n,a,j, 并且成功的获取了user.name;user.age;user.job属性的值。name:n 这种语法表示读取user.name的属性。并且把它的值存在n变量之上。

这种语法和传统的对象字面量的语法相反。传统的是左侧为名,右侧为值,但是在当前这个案例中。左侧为值,右侧为名。

注意:依然可以给变量别名添加默认值,依然是在本地变量名称后添加等于默认值。比如:

let user = {
    name:undefined,
    age:20,
    job:'前端工程师'
};

let {
    name:n = '颜色',
    age:a,
    job:j
} = user

console.log(n)   //颜色
console.log(a)
console.log(j)

在以上这个案例中 n 变量有一个默认值 “颜色” 这个变量值。会在对应的对象属性不存或为undefiend时启用。

5.2.4 嵌套的对象解构

类似于对象字面量的语法,可以使到嵌套的对象结构中的数据,比如:

let user = {
    name:"颜苗",
    love:{
        s:{
            sex:"男",
            number:5
        },
        e:{
            sex:"女",
            number:7
        }
    }
}

let {
    love:{s}
} = user

console.log(s)   // {sex: "男", number: 5}

以上案例在解构中使用了花括号,表示应当下行到user对象中的love属性内部对找s属性,这里需要记住。每当有一个冒号(:)在解构中模式中出现,则表示冒号(:)之前的标识符代表需要检查的位置,而右则是赋值的目标。当右侧存在花括时,表示目标被嵌套对象更深的一层当中。

如果需要更进一步,在对的嵌套解构名同样能为本地变量使用不同的名称,比如:

let { love:{s:php}} = user

以上user.love.s的值被赋值给了一个新的变量php。

5.3 数组解构

数组解构和对象解构在语法上面非常的相似,只不过就是把对象字面量换成了数组字面量。

数组解构时,解构作用在数组的内部位置上,而不是作用在对象的具名属性上。比如:

let users = ["赵中","颜苗","周斯佳"];
let a = users[0],b=users[1]  //es5
let [ z,y ] = users;
console.log(z,y)  // 赵中 颜苗 

以上从数组解构中取出了赵中和颜苗,并且赋值给了z和y变量。这些值被选择。取决于他们在数组中的位置。实际的变量名称是任意的。(和位置无关)。任何没有在解构模式明确指定的值都会被忽略。要注意的是,数组本身没有变任何方式方法改变。

let [,,j] = users;
console.log(j)  //周斯佳

以上案例中加的逗号是为了数组前面的项提供的占位符。使用这种方法可以取出数组任意位的值。不用提供其它的变量名。

需要注意的是。在使用var,let,const进行数组解构时,必须提供初始化值。

我们还可以在赋值表达式中使用数组解构。但是和对象解构不同,不用把表达式包含在圆括号内,比如:

let users = ["赵中","颜苗","周斯佳"],
    z = "张也",
    y = "叶彬";

[z,y] = users;

console.log(z,y)  // 赵中 颜苗

在ES5如果想要互相两个变量的值,需要使用第三个变量作训临时变量,比如:

var a = 10,
    b = 20;

var c = a;
a = b;
b = c;

console.log(a,b)

以上这个C变量对于互相是非常重要的。但是如果使用了es6的数组解构。就不用这个临时变量了。比如:

var a = 10,
    b = 20;
[a,b] = [b,a]
console.log(a,b) // 20 , 10

以上这个案例,赋值语句左侧的解构其它的数组解构的例子是一样的。右侧则是为了互换而临时创建的数组字面量。b和a的值分别被复制给了临时数的第一个和第二个位置。并且进了解约。结果就是两个变量的值进行了互相

和对象解构赋值相同的是,若等号右则的计算结果,为null或undefined,数组解构赋值表达式会发生错误。

5.3.1 数组解构默认值

数组同样允许在数组任意位置指定默认值,如果指定位不存在,或着值是undefined,这个默认值就会被使用.比如:

let users = ["颜苗"];
let [a,b = '赵中',c = '大鹏'] = users
console.log(a,b,c) //颜苗 赵中 大鹏

以上代码中users数组只有一个项,因此并没有为b,c提供匹配的项.然后我们又给他们加了默认值.所以就是对就的名字

5.3.2 嵌套

和对象相似,可以用对象的方式来解构嵌套的数组.也就是可以整个解构中插入另一个数组.就以下这样

let users = ["颜苗",['orange','yellow'],'赵中'];
let [first,[color]] = users
console.log(first,color)

以上first表示users数组中的颜苗,而内层数组orange,包含在里面的一个数组中.因此我们想要拿到它就必须也要加一个方括号[].可以使用任意深度的嵌套.

5.3.3 剩余项

数组解构剩余项,可以使用 ... 语法来把剩余项的项目赋值给一个变量,比如:

let users = ["颜苗",['orange','yellow'],'赵中'];
let [first,...arr] = users
console.log(first,arr)  //颜苗 (2) [Array(2), "赵中"]
console.log(arr.length) //2
console.log(arr[0][0]) //orange

以上这个案例,第一个项给了first,剩余项给了一个新的变量arr

剩余项的另一个功能克隆功能。比如:

首先不淡这个剩余项,我们用es5的方法( concat() )来实现克隆

var arr = ['a','b','c'];
var newArr = arr.concat();
newArr.push('d')
console.log(newArr,arr)

尽管concat方法的本意是合并两个数组。但是如果不使用任何的参数来调用这个方法。就会得到个新的数组。但是如果在es6中,我们可以这样做。比如:

let arr = ['a','b','c'];
let [...newArr]  = arr;
newArr.push('d')
console.log(newArr,arr)

以上这个方法,并没有比concat好多少,但是在使用上面也算是一个技巧。

剩余项必须是解构模式中最后的部分,之后不能再有任何的东西。否则就会报语法错误。

5.3.4 混合解构

对象和数组解构被用在一起,用来创建更加复杂的数据形式。大多数时候可以用于ajax数据效果的时候,体现特别的明显。比如:

const  obj = {
    isCheck:true,
    name:"obj",
    local:{
        access:{
           x:100,
           y:300
        }
    },
    news:['尽管concat方法的本意是合并两个数组。但是如','混合解构']
};

let {
    local:{
        access
    },
    news:[firstNews]
} = obj;

console.log(access,firstNews)

以上obj.local.access和obj.news[0]被取出来。并别存给了access和firstnews中。这里需要注意和记住的是解构模式中 local:和 news:只是对应obj 这个对象中属性的位置。混合使用。obj对象的任何部分都能被提出来。对于ajax中返回给我们的json数据来说。 这种方法尤其高效,因为不需要去搜索整个结构.

5.4 参数解构

一个不能被忽略的场景就是,传递函数参数时。当我们的函数接收大量的可选参数时的一个常用的模是创建一个options对象。会在其中包含符加的参数,比如:

// options上的属性表示符加参数
function ajax(url,data,options){
    options = options || {}
    let time = options.time,
        success = options.success;
}

ajax('1.php','张志翔',{
    time:3000,
    success:function(){
        console.log(success)
    }
})

以上这样的案例大家如果去看一些js库的源码,你会看到很多类似这样的代码。在这个ajax函数中,url和data是必须的。而options对象中的time,success则不是必须的。这种方法是有效的,但是无法通过查看函数的定义就能知道我想要输入什么样的代码。必须去阅读开发文档或是源码。

但是用了参数解构之后,可以在第一时间更清楚明白的去标明函数期望输入的参数值。使用对象或数组模式替代具名参数。比如:

function ajax(url,data,{time,success}){
    //其它代码
}

ajax('1.php','张志翔',{
    time:3000,
    success:function(){
        console.log(success)
    }
})

以上这个案例,第三个参数使用了解构来抽取必要的数据。那么现在对于开发者来说,解构之外参数是必须的,而可选的项目放在参数组中。同时如果使用了第三个参数其中应该需要的值,是极期明确。如果没有传值。他们的值就是undefined.

但是如果我们没有给解构传参。在默认情况下,调用函数时未给参数解构传值会报错:比如:

ajax('1.php','张志翔')

在实际调用时,第三个参数的缺失。就相当于undefiend,会导致一个错误,因为参数解构实际上只是解构了声明的简写、当我们的ajax()函数被调用时。js的引擎会修改我们的代码为如下效果

function ajax(url,data,options){
     let {time,success} = options
    //  其它代码
}

因为赋值过程中。右侧的值为null 或是 undefined时。解构会抛出错误,那么也就是未向ajax()函数传递第三个参数时同样也会出错。但是如果我们的要求是可先的。我们可以这样做:

function ajax(url,data,{time,success} = {}){
   console.log('其它代码')
}

ajax('1.php','张志翔')

以上这个案例第三个参数给了一个空对象作为默认值.也就是说没有向函数传递第三个参数.则里面的time,success的值都是undefiend.这时就不会报错.

基于以上的原理,可以为参数解构提供默认值.就和解构赋值时的操作一样.那么也就可以在其中每个参数的后面添加默认值.比如:

function ajax(url,data,{time = 5000,success = true} = {}){
   console.log('其它代码')
}

ajax('1.php','张志翔')

以上代码中参数解构给每个属性都提供了默认值.所以我们可以避免检查指定的属性是否有被传入 .以确保在没有被传入数据的时候,可以使用正确的类型值.而整个解构的参数同样有一个默认值,就是一个空对象,可以让这个参数成为一个可选参数,这个案例稍微要复杂一点.但是可以确保每个参数都有可用的值,而不必加必要检查,所以这样的付出是值得的.

总结

  1. 解构会让我们操作对象和数组时变的更加容易,可以把数据分离并且只拿到你想要的信息.

  2. 对象解构模式可以让你从对象中进行取值,而数组模用于数组.

  3. 对象和数组解构都可以提供默认值.

  4. 特加需要注意的是,如果赋值操作符也就是等号右侧的值为null或undefined的时候,两种模都会报错.

  5. 可以在深层的嵌套中使用解构.可以是任意深度.

  6. 在使用var,let,const,的解构声明创建的变量.必须要提供初始化值.允许我们把值解构到对象属性或已经存在的变量上

  7. 参数解构,可以让选项对象变的更加的清楚透明.

Leave a Reply

Your email address will not be published.