解构赋值

对象解构

必须用圆括号包裹解构赋值语句,这是因为暴露的花括号会被解析为代码块语
句,而块语句不允许在赋值操作符(即等号)左侧出现。圆括号标示了内部的花括号并不是
块语句、而应该被解释为表达式,从而完成赋值操作。

1
2
3
4
5
6
7
8
9
10
11
let node = {
type: "Identifier",
name: "foo"
},
type = "Literal",
name = 5;
// 使用解构来分配不同的值
({ type, name } = node);

console.log(type); // "Identifier"
console.log(name); // "foo"

顺序不同也没事

也可以结合冒号和等号一起使用

1
let {width: w = 100, height: h = 200, title} = options;

实际上是这样 let { foo: foo, bar: bar } = { foo: “aaa”, bar: “bbb” };

对 type 与 name 的赋值正常进行,同时 node 也被传入
了 outputInfo() 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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"

赋值给非同名本地变量

1
2
3
4
5
6
let node = {
type: "Identifier"
};
let { type: localType, name: localName = "bar" } = node;
console.log(localType); // "Identifier"
console.log(localName); // "bar"

嵌套的对象解构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

每当有一个冒号在解构模式中出现,就意味着冒号之前
的标识符代表需要检查的位置,而冒号右侧则是赋值的目标。当冒号右侧存在花括号时,表
示目标被嵌套在对象的更深层次中。

数组解构

数组解构的语法看起来与对象解构非常相似,只是将对象字面量替换成了数组字面量。数组
解构时,解构作用在数组内部的位置上,而不是作用在对象的属性名上

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

在 ES6 中互换值

1
2
3
4
5
6
7
let a = 1,
b = 2;

[a, b] = [b, a];

console.log(a); //2
console.log(b); //1

引用

1
2
3
4
5
6
7
8
let a = 1,
b = 2;
let arrayA = [7,7];
let arrayB = [8,8];
[a, b] = [arrayA, arrayB];
arrayA[0] = 8
console.log(arrayA); //[8, 7] 而不是[7,7]
console.log(arrayB); //[8, 8]

数组嵌套解构

1
2
3
4
5
6
let colors = ['red', 'yellow', ['green', 'lightgreen'], 'blue'];

let [firstColor, [secondColor]] = colors;

console.log(firstColor) //red
console.log(secondColor) //y

参数解构

原先

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// options 上的属性表示附加参数
function setCookie(name, value, options) {
options = options || {};
let secure = options.secure,
path = options.path,
domain = options.domain,
expires = options.expires;
// 设置 cookie 的代码
}
// 第三个参数映射到 options
setCookie("type", "js", {
secure: true,
expires: 60000
});

now

1
2
3
4
5
6
7
function setCookie(name, value, { secure, path, domain, expires }) {
// 设置 cookie 的代码
}
setCookie("type", "js", {
secure: true,
expires: 60000
});

执行时不能缺少option参数

1
2
3
4
5
function setCookie(name, value, options) {
//好比
let { secure, path, domain, expires } = options;
// 设置 cookie 的代码
}

参数解构的默认值

1
2
3
4
5
6
7
8
9
10
function setCookie(name, value,
{
secure = false,
path = "/",
domain = "example.com",
expires = new Date(Date.now() + 360000000)
} = {}
) {
// ...
}

上面的参数解构只有一个缺点,也就是当传入参数值为 null 时会引发程序异常。只有
null 与 undefined 是无法被解构的,而传入 undefined 会触发默认参数的使用条
件,从而避免了异常;但传入 null 就不会有这么幸运了,它既不会触发默认参数,也
不能被解构,从而导致异常。

默认值可以是更加复杂的表达式甚至可以是函数调用,这些表达式或函数只会在这个变量未被赋值的时候才会被计算。

1
2
3
4
5
6
// 默认值
// 只会提示输入姓氏
let [name = prompt('name?'), surname = prompt('surname?')] = ["Julius"];

alert(name); // Julius (来自数组)
alert(surname); // 你输入的值

练习

1
2
3
4
5
6
7
8
9
10
11
以下是一个 salaries 对象:
let salaries = {
"John": 100,
"Pete": 300,
"Mary": 250
};
新建一个函数 topSalary(salaries),返回拥有最高薪资的人。
1. 如果 salaries 是空的,函数应该返回 null
2. 如果有多个最高薪资的人,返回其中任意一个。

提示:使用 Object.entries 和解构语法来遍历键/值对。

answer1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let salaries = {
"John": 100,
"Pete": 300,
"Mary": 250
};

// topSalary(salaries)

function topSalary(salaries) {
const orderList = Object.entries(salaries).sort((a, b) => {
return b[1] - a[1]; //通过值降序排序
})
return orderList[0]
}

let money = topSalary(salaries);
console.log(money);

answer2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function topSalary(salaries) {

let max = 0;
let maxName = null;

for(let [name, salary] of Object.entries(salaries)) {
if (max < salary) {
max = salary;
maxName = name;
}
}

return maxName;
}

补充

1
2
3
4
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
1
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'

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

1
2
3
4
5
let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。