文章目录
常用的解构赋值
1、字符串
// 1、字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。
{
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"
}
// 2、类似数组的对象都有一个length属性,因此还可以拥有length属性的对象进行解构赋值。
{
let { length } = 'hello';
console.log('length: ', length);
}
2、对象的解构赋值可以取到继承的属性
{
// 1.解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。
let { toString: s } = 123;
console.log(' s: ', s); // ƒ toString() { [native code] }
console.log(s === Number.prototype.toString); // true
/* 这里的s为什么变成了函数toString()了呢?这是因为123如果转为对象,可能是这样:
{123: '123'}
123: "123"
[[Prototype]]: Object
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
这里的123转对象的规则是什么,转成什么样子其实我也不太清楚,这里是我假象的,但是不管怎么转,顶层都会有toString方法。
原型链上有toString()方法,而对象的解构赋值可以取到继承的属性,自然s就是toString方法了。*/
}
{
// 2. 解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。
// 由于undefined和null无法转为对象,所以对它们进行解构赋值,都会报错。
let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
// Cannot destructure property 'prop' of 'undefined' as it is undefined.
}
3、交换变量的值
{
let x = 1;
let y = 2;
[x, y] = [y, x];
console.log(x, y);//2 1
//上面代码交换变量x和y的值,这样的写法不仅简洁,而且易读,语义非常清晰。
}
4、从函数取出多个值
{
// 函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。
function example() {
return {
foo: "val1",
bar: "val2"
};
}
let { foo, bar } = example();
console.log(foo, bar);//val1 val2
}
5、函数参数的定义(*)
{
// 解构赋值可以方便地将一组参数与变量名对应起来。
// 1.参数是一组有次序的值
function f([x, y, z]) {
console.log('z: ', z);
console.log('y: ', y);
console.log('x: ', x);
}
console.log(f([1, 2, 3])); // z: 3 y: 2 x: 1
// 2.参数是一组无次序的值 解构赋值可以方便地将一组参数与变量名对应起来。
function f({ x, y, z }) {
return [x, y, z]
}
console.log(f({ z: 3, y: 2, x: 1 })); //(3) [1, 2, 3]返回数组形式
//返回的形式完全可以由需求决定,数组、对象都可以。
}
6、函数参数的解构也可以使用默认值。(*)
{
function move({ x = 0, y = 0 } = {}) {
return [x + y]
}
console.log(move({ x: 1, y: 2 })); // 3
console.log(move({ x: 999 })); // 999
// 做一个分析:
// 这里{ x: 999 }为实参,传入后,{ x = 0, y = 0 }就要与{ x: 999 }进行模式匹配,发现y找不到对应模式,故y=undefined,此时y解构失败,就会启用默认值y = 0;记住解构失败,启用默认值就好。
console.log(move({})); // 0
console.log(move()); // 0
console.log("-----------------------");
// 上面代码中,函数move的参数是一个对象,通过对这个对象进行解构,得到变量x和y的值。如果解构失败,x和y等于默认值。
}
7、为函数move的参数指定默认值(*)
{
function move({ x, y } = { x: 0, y: 0 }) {
return [x, y]
}
// 下面代码是为函数move的参数指定默认值,而不是为变量x和y指定默认值,所以会得到与前一种写法不同的结果。
// 刚开始我一下子也没看明白这是怎么回事,但是突然想起来函数传参时的形参与实参关系。
move({ x: 1, y: 2 }) //>>>>> [1, 2]
// 这里move的x\y都能匹配到对应的模式,既{ x: 1, y: 2 },所以正常输出
move({ x: 999 }) //>>>>> [999, undefined]
// 这里模式x能正常匹配,但是y没有传入,y取值时找不到,所以为undefined
move({}) //>>>>> [undefined, undefined]
// 这里x\y都找不到对应匹配的模式,所以都为undefined
move() //>>>>> [0, 0]
// 这里相当于没有传入模式,此时才会使用参数解构的默认值,既{ x: 0, y: 0 }
// 那么,move({ q: 1, y: 2 })会返回什么呢?
// 根据对象的解构匹配模式的定义,很明显,只有y能正常匹配模式,找不到模式x,自然x就为undefined,所以输出为:[undefined, 2]
}
8、解构赋值对提取 JSON 对象中的数据,尤其有用。(*)
{
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number); // 42, "OK", [867, 5309]
// 上面代码可以快速提取 JSON 数据的值。
}
9、ES6…扩展操作符骚操作
// 复制和合并数组变得更为简洁。不需要使用 concat() 方法或 slice() 方法,一个 ...操作符已经足够:
{
const arr1 = [10, 20, 30];
const copy = [...arr1];
console.log(copy); // → [10, 20, 30]
const arr2 = [40, 50];
const merge = [...arr1, ...arr2];
console.log(merge); // → [10, 20, 30, 40, 50]
}
10、将数组作为一个需要单独一个个传入参数的函数的参数
{
const arr = [10, 20, 30]
// equivalent to console.log(Math.max(10, 20, 30));
console.log(Math.max(...arr)); // → 30
}
11、 对象属性展开复制(*)
{
const obj1 = {
a: 10,
b: 20
};
const obj2 = {
...obj1,
c: 30
};
console.log(obj2); // → {a: 10, b: 20, c: 30}
// 如果存在相同的值 后者覆盖前者
{
const obj2 = {
...obj1,
a: 30
};
console.log(obj2); // → {a: 30, b: 20}
}
}
12、合并对象 类似于object.assign(*)
{
const obj1 = { a: 10 };
const obj2 = { b: 20 };
const obj3 = { c: 30 };
// ES2018
console.log({ ...obj1, ...obj2, ...obj3 });
// → {a: 10, b: 20, c: 30}
// ES2015
console.log(Object.assign({}, obj1, obj2, obj3));
// → {a: 10, b: 20, c: 30}
}