解构(Destructuring)是ES6新增的特性。数组和对象(Object)的一个作用是把一些值组合打包在一起。与之相对,解构就类似把数组里的值或对象的属性解包。使用解构赋值语法可以很简便地把数组的值或对象的属性赋值给单独的变量。
语法
var a, b, rest;
[a, b] = [10, 20];
console.log(a); // 输出10
console.log(b); // 输出20
[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(a); // 输出10
console.log(b); // 输出20
console.log(rest); // 输出数组后面的值[30, 40, 50]
({a, b} = {a: 10, b: 20});
console.log(a); // 输出10
console.log(b); // 输出20
({a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40});
数组解构
基本的用法
let input = [1, 2];
let [first, second] = input;
console.log(first); // 输出 1
console.log(second); // 输出 2
这里创建了first和second两个变量,input数组按索引依次对first和second赋值。这等同于
first = input[0];
second = input[1];
显然,使用解构赋值更加简便明了。
交换变量
[first, second] = [second, first];
函数参数
function f([first, second]: [number, number]) {
console.log(first);
console.log(second);
}
f([1, 2]);
余项变量
使用...语法来创建变量,数组的余项构成新的数组将赋值给此变量。
let [first, ...rest] = [1, 2, 3, 4];
console.log(first); // 输出1
console.log(rest); // 输出余项数组 [ 2, 3, 4 ]
当然,如果不需要处理余项,则可以把余项变量去掉。
let [first] = [1, 2, 3, 4];
console.log(first); // 输出 1
跳过元素
也可以留空来跳过元素:
let [, second, , fourth] = [1, 2, 3, 4];
这里跳过了第一和第三个元素。
对象解构
对象解构可以把对象的属性以简便的方式赋值给单独的变量。
基本用法
let o = {
a: "foo",
b: 12,
c: "bar"
};
let { a, b } = o;
例子里新建了变量a和b,并把对象的o的属性a和b分别赋值给它们,o.c不需要用到,可以忽略。
不声明对象变量,使用括号括起来可以对对象直接解构赋值:
({ a, b } = { a: "baz", b: 101 });
例子里{ a, b } = { a: "baz", b: 101 }使用了括号括起来。
余项变量
和数组解构的余项变量一样,对象解构使用...语法创建变量,对象余下的属性构成新的对象赋值给此变量。
let o = {
a: "foo",
b: 12,
c: "bar"
};
let { a, ...passthrough } = o;
let total = passthrough.b + passthrough.c.length;
此例里,passthrough值为{b:12,c:'bar'}。
重命名属性
除了使用原来的属性名作为变量来接收解构的值外,也可以对属性变量重命名。重命名的语法:
let o = {
a: "foo",
b: 12,
c: "bar"
};
let { a: newName1, b: newName2 } = o;
console.log(newName1); //输出foo
console.log(newName2); //输出12
重命名也是避免和原来属性重名。
默认值
可以对解构的变量赋一个默认值,避免解构对象属性的值为undefined。
function keepWholeObject(wholeObject: { a: string, b?: number }) {
let { a, b = 1001 } = wholeObject;
}
wholeObject的属性为可选,当它的值为undefined时,解构变量b值为默认值1001。
函数声明
解构也可以用在函数声明里:
type C = { a: string, b?: number }
function f({ a, b }: C): void {
// ...
}
这里定义了类型C,并在声明函数f时,把类型C的属性解构赋值给函数变量a和b。
函数声明时赋默认值:
function f({ a, b } = { a: "", b: 0 }): void {
// ...
}
f(); //默认值为{ a: "", b: 0 }
扩展(Spread)
使用扩展运算符可以一个数组添加到另外一个数组,或者把一个对象的属性添加到另外一个对象。使用...语法来扩展数组和对象。
数组扩展
let first = [1, 2];
let second = [3, 4];
let bothPlus = [0, ...first, ...second, 5];
bothPlus为扩展的数组,它的值扩展后卫[0,1,2,3,4,5]。
对象扩展
let defaults = { food: "spicy", price: "$$", ambiance: "noisy" };
let search = { ...defaults, food: "rich" };
search为扩展后的对象,对象的扩展存在属性相同时,后面的属性的值覆盖前面的值。上面的例子里,后面food的值'rich'将会覆盖defaults里的food的值。
对象的扩展有两个限制:
- 不能扩展方法
- 不允许扩展来自泛型函数的类型参数