ES6 解构功能

2,021 阅读6分钟

解构 是ES6中添加的一项简化任务的新特性。ES6为对象和数组都加入了解构功能,将数据结构打散的过程变得更加的简单,然后从打散的数据中获取所需的信息。接下来介绍解构特性如何应用到对象和数组中。

对象解构

解构声明变量

对象解构语法特别简单,在赋值操作符左边放置一个对象的字面量。

var object = {
    name: "ES6",
    age: 2015
}
var { name, age } = object;
console.log(name);  //  "ES6"
console.log(age);   //  "2015"

上述代码中,object.name 的值存储在 name 变量中,object.age 的值存储在 age 变量中,name 和 age 都是局部声明的变量。
注意:使用解构声明变量要记得初始化且赋值表达式右值不能为 null 或 undefined ,否则会抛出语法错误。

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

解构赋值

var object = {
        name: "ES6",
        age: 2015
    },
    name,
    age;
({ name, age } = object);
console.log(name);      //  "ES6"
console.log(age);       //  "2015"

{ name, age } = object; //注意:这样做会抛出语法错误

上述代码,通过解构赋值的方法,重新为 name, age 这两个变量赋值。注意,一定要用 ( ) 包裹解构赋值语句,由于JS引擎将一对开放得 {...} 视为代码块,在语法规定中,赋值语句左边不允许出现代码块语句。

默认值

使用解构赋值表达式时,如果对应局部变量名称在对象中不存在时,该局部变量会赋值为undefined。当指定属性不存在时,可以为该属性定义默认值。

var object = {
    name: "ES6",
    age: 2015
};

var { name, age, type } = object;
console.log(name, age, type);    // "ES6", "2015", undefined


var { name, age, type = "JavaScript" } = object;
console.log(name, age, type);   //  "ES6", "2015", "JavaScript"

第二处代码为变量 type 设置了默认值 "JavaScript" ,只有当object上没有type属性或type属性为 undefined 时该默认值才生效。

非同名局部变量赋值

上面的示例代码都是对象中同名的属性为同名的局部变量来声明或赋值,那不同名的局部变量怎么办?ES6中扩展语法可以满足你的需求。

var object = {
    name: "ES6",
    age: 2015
};

var { name: newName, age: newAge} = object;
console.log(newName, newAge);   //  "ES6", "2015"

//结合默认值
var { name: newName, type: newType = "JavaScript" } = object;
console.log(newName, newType);  //  "ES6", "JavaScript"

非同名局部变量声明语法格式:

let { 对象属性: 局部变量名 = 默认值 } = 对象

嵌套对象解构

解析嵌套对象语法与对象字面量语法相似,可以将对象拆解获取你想要的信息。

var object = {
    name: "ES6",
    age: 2015,
    key: {
        add1: "Symbol",
        add2: "Set、Map"
    }
};

var { key: { add1, add2: newAdd2 } } = object;
console.log(add1, newAdd2);   //  "Symbol", "Set、Map"

在解构模式中使用{},表示找到object对象中key属性后,深入一层查找 add1 和 add2 的属性,然后 add1 的值赋给 add1 局部变量 ,add2 的值赋给 newAdd2 局部变量。

数组解构

解构声明变量

数组解构相比对象解构就简单多了,它使用数组字面量,且解构操作全部在数组内完成。

var array = [ "aa", "bb", "cc"];
var [ key1, key2, key3 ] = array;
console.log(key1, key2, key3);  // "aa", "bb", "cc"

这样看确实比对象解构要简单明了。当然我们也可以忽略某些元素,直接获取想要的元素。

var array = [ "aa", "bb", "cc"];
var [ , , key3 ]= array;
console.log(key3);  //  "cc"

通过逗号占位符来忽略不想要的元素。

解构赋值

与对象解构赋值不同的是:不需要使用()包裹解构表达式。

var array = [ "aa", "bb", "cc"],
    key1 = 11;
[ key1 ] = array;
console.log(key1);  //  "aa"

在ES5中交换两个变量的值,则须引入第三个临时变量:
var a = 1,
    b = 2,
    c;

c = a;
a = b;
b = c;
console.log(a, b);   // 2, 1

ES6中使用数组解构赋值语法,就不需要临时变量:

var a = 1,
    b = 2;

[ a, b ] = [ b, a ];
console.log(a, b);  //  2, 1

这个数组解构赋值看上去想镜像赋值一样。首先执行赋值操作符右边,解构由 b, a 变量组成的临时数组,再执行左边赋值操作,a 变量获取右边临时数组的第一个元素,b 变量获取右边临时数组的第二个元素,最终结果变量互换了值。

默认值

数组解构赋值表达式也可以添加默认值,与对象解构一样。

var array = [ "aa", "bb" ],
[ , , key3 = "cc" ] = array;
console.log(key3);  //  "cc"

嵌套数组解构

var array = [ "aa", [ 11, 22, 33 ] ];
var [ key1, [ key2, key3 ] ] = array;
console.log(key1, key2, key3);  //  "aa", 11, 22

嵌套数组解构与嵌套对象解构语法类似,在数组中插入另一个数组模式,即可深入到下一层。

混合解构

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

// 示例1:
var object = {
    name: "ES6",
    array: ["Promist","Set、Map","class","Proxy"]
};

var { array: [ value1, value2, value3 ] } = object;
console.log(value1, value2, value3);

//示例2:
var array = [ 
    {
        name: "ES6",
        age: 2015
    },
    {
        name: "ES7",
        age: 2016
    }
];

var [ object1, { name, age } ] = array;
console.log(object1);       //  Object { name: "ES6", age: 2015 }
console.log(name, age);     //  "ES7" 2016

看起来好像挺复杂,其实记住对象解构和数组解构的区别,就能轻易写出混合解构。

解构参数

解构模式也适应于函数参数传递的过程。

function fun( fn, { times, delay } ){
    for(var i = 0; i < times; i++){
        setTimeout(fn, delay * (i + 1));
    }
}
var fn = function (){
    console.log("hello ES6.");
}

fun(fn, {times: 10, delay: 2000});  
// 每2000毫秒打印一次 "hello ES6." ,总共十次

fun(fn);
// 抛出语法错误

上述示例通过解构参数从对象中获取必要的 times, delay 值用于函数内部,这种解构参数对于调用 fun 函数的使用者来说更加的清晰。注意上述代码最后一个语句: 当调用函数时不提供被解构的实参,会抛出语法错误。
文章前面提到过,解构功能必须初始化,所以这时候给解构加上默认值就非常有必要,幸好 ES6 为我们加入了函数形参提供默认值的过程。如下:

function fun( fn, { times, delay } = { times: 10, delay: 1000 }){
   //执行代码
}
var fn = function (){
   //执行代码
}
fun(fn);   //  完美执行

现在函数使用起来更方便了,第一个对象字面量是解构参数,第二个为默认值。但是如果解构参数越多,那函数参数就会越冗余。这时应该在外部定义一个配置对象来作为默认值会更好。

var config = {
   times: 10, 
   delay: 1000
};

function fun(fn, 
   { 
       times = config.times,
       delay = config.delay
   } = config
){
   //执行代码
}

这段代码中,默认值是config对象,此外我还为解构参数中每一项绑定了默认值。这样我就可以只传递 times 或 delay 的实参了,并不需要都给实参。