JavaScript < ES5、ES6、ES7、… >ECMAScript 6

ES6(十三):解构赋值

2019-01-30  本文已影响12人  CodeMT

前面的话


  我们经常定义许多对象和数组,然后有组织地从中提取相关的信息片段。在ES6中添加了可以简化这种任务的新特性:解构。解构是一种打破数据结构,将其拆分为更小部分的过程。本文将详细介绍ES6解构赋值

引入

ES5中,开发者们为了从对象和数组中获取特定数据并赋值给变量,编写了许多看起来同质化的代码

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

对象解构

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

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

【解构赋值】

到目前为止,我们已经将对象解构应用到了变量的声明中。然而,我们同样可以在给变量赋值时使用解构语法

let node = {
  type: "Identifier",
  name: "foo"
},
type = "Literal",
name = 5;// 使用解构来分配不同的值
({ type, name } = node);
console.log(type); // "Identifier"
console.log(name); // "foo"

[注意]一定要用一对小括号包裹解构赋值语句,JS引擎将一对开放的花括号视为一个代码块。语法规定,代码块语句不允许出现在赋值语句左侧,添加小括号后可以将块语句转化为一个表达式,从而实现整个解构赋值过程

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

[注意]解构赋值表达式(也就是=右侧的表达式)如果为nullundefined会导致程序抛出错误。也就是说,任何尝试读取nullundefined的属性的行为都会触发运行时错误

【默认值】

使用解构赋值表达式时,如果指定的局部变量名称在对象中不存在,那么这个局部变量会被赋值为undefined

let node = {
  type: "Identifier",
  name: "foo"
};
let { type, name, value } = node;
console.log(type); // "Identifier"
console.log(name); // "foo"
console.log(value); // undefined
let node = {
  type: "Identifier",
  name: "foo"
};
let { type, name, value = true } = node;
console.log(type); // "Identifier"
console.log(name); // "foo"
console.log(value); // true

【为非同名局部变量赋值】

如果希望使用不同命名的局部变量来存储对象属性的值,ES6中的一个扩展语法可以满足需求,这个语法与完整的对象字面量属性初始化程序的很像

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

【嵌套对象解构】

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

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
let node = {
  type: "Identifier",
  name: "foo",
  loc: {
    start: {
      line: 1,
      column: 1 
    },
    end: {
      line: 1,
      column: 4 
    }
  }
};// 提取 node.loc.start
let { loc: { start: localStart }} = node;
console.log(localStart.line); // 1
console.log(localStart.column); // 1

数组解构

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

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

【解构赋值】

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

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

【变量交换】

数组解构语法还有一个独特的用例:交换两个变量的值。在排序算法中,值交换是一个非常常见的操作,如果要在ES5中交换两个变量的值,则须引入第三个临时变量

// 在 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

[注意]如果右侧数组解构赋值表达式的值为nullundefined,则会导致程序抛出错误

【默认值】

也可以在数组解构赋值表达式中为数组中的任意位置添加默认值,当指定位置的属性不存在或其值为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中,开发者们经常使用concat()方法来克隆数组

// 在 ES5 中克隆数组
var colors = [ "red", "green", "blue" ];
var clonedColors = colors.concat();
console.log(clonedColors); //"[red,green,blue]"
// 在 ES6 中克隆数组
let colors = [ "red", "green", "blue" ];
let [ ...clonedColors ] = colors;
console.log(clonedColors); //"[red,green,blue]"

[注意]在被解构的数组中,不定元素必须为最后一个条目,在后面继续添加逗号会导致程序抛出语法错误

混合解构

可以混合使用对象解构和数组解构来创建更多复杂的表达式,如此一来,可以从任何混杂着对象和数组的数据解构中提取想要的信息

let node = {
  type: "Identifier",
  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

【解构参数】

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

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

【必须传值的解构参数】

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

// 出错!setCookie("type", "js");
function setCookie(name, value, options) {
  let {
    secure, path, domain, expires 
  } = options;// 设置 cookie 的代码
}
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 setCookieDefaults = {
  secure : false,
  path : "/",
  domain : "example.com",
  expires : new Date(Date.now() + 360000000)    
}
function setCookie(name, value,{
  secure = setCookieDefaults.secure,
  path = setCookieDefaults.path,
  domain = setCookieDefaults.domain,
  expires = setCookieDefaults.expires        
}=setCookieDefaults) {
  // ...
}

其他解构

【字符串解构】

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

const [a, b, c, d, e] = 'hello';
console.log(a);//"h"
console.log(b);//"e"
console.log(c);//"l"
console.log(d);//"l"
console.log(e);//"o"
const {length} = 'hello';
console.log(length);//5

【数值和布尔值解构】

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

let {toString:s1} = 123;
console.log(s1 === Number.prototype.toString);//true
let {toString:s2} = true;
console.log(s2 === Boolean.prototype.toString);//true
let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
上一篇 下一篇

猜你喜欢

热点阅读