一、解构本质
解构赋值本质就是给变量赋值,赋值的方式就是模式匹配
二、()用法
解构赋值对象如果不let声明,JS就认为它是一个语法块(块级作用域)
let a;
{ a } = { a: 1 };
console.log(a) // 报错
解决方法:用括号包裹,变成表达式
let a;
({ a } = { a: 1 });
console.log(a) // 1
只有这种情况加括号不会报错,取余情况均会报错
当用 let、var 的方式来声明,只要加了括号就报错
加了括号就是表达式,语法不通过,所以报错
let [(a)] = [1];
let {(a):b} = {};
let ({a:(b)}) = {};
let ({a:b}) = {}; // 全报错
函数的形参也不能加括号
因为上一节课已经得出结论:函数的形参也是用let声明的,所以加上括号就会报错
function foo(([z])) {
return z;
}
console.log(foo([1])); //报错
模式匹配必须l模式一样才能匹配
[b] = [3];
console.log(b); // 3
([b]) = [3];
console.log(b); // 报错 匹配规则不对,所以匹配不成功
({a: (b) = {}})
console.log(b); // {} 没有匹配 JS认为{a: (b) = {}}是一个对象,a是属性,b是属性值 默认值为{}
var a = {};
[(a.b)] = [3]; // 以数组的匹配模式 给a对象的b属性赋值3
console.log(b); // 报错 匹配了 但必须通过a.b访问
let is not defined
一般情况下就是因为 let = (…) 导致的错误,let不能声明表达式
三、解构妙用
模式匹配可以给对象的属性赋值
let a1 = [1, 2, 3], obj2 = {};
[obj2.a, obj2.b, obj2.c] = a1;
console.log(obj2.a, obj2.b, obj2.c); // 1,2,3
计算属性解构
数组是特殊的对象,也支持对象的匹配规则
let arr = [1, 2, 3];
let { 0: first, [arr.length - 1]: last } = arr;
console.log(first, last); // 1,3
字符串拼接属性
let a = 'x', b = 'y', obj = {};
// { a: obj[a + b] } = { a: 2 } 这里不通过的原因是它认为{}是一个块级作用域,所以要把它变成表达式,这样才能解构
({ a: obj[a + b] } = { a: 2 });
console.log(obj.xy); // 2
交换值
let a = 10, b = 20;
[b, a] = [a, b]
console.log(a, b); // 20 10
模式匹配允许匹配同源属性(同一个源属性)
只要匹配的源属性存在,就可以写多个相同的属性
但是变量不能相同,因为这样就重复声明了
let { a: x, a: y } = { a: 1 };
console.log(x, y); // 1 1
let { a: x, a: x } = { a: 1 };
console.log(x, x); // 报错,重复声明
解构的默认参数
在解构中使用对象或是数组的时候,慎用(可读性非常差)
var x = 200,
y = 300,
z = 100;
var obj1 = { x: { y: 42 }, z: { y: z } };
({ y: x = { y: y } } = obj1); // x = {y: 300}
({ z: y = { y: z } } = obj1); // y = {y: 100}
({ x: z = { y: x } } = obj1); // z = {y: 42}
console.log(x, y, z); // { y: 300 } { y: 100 } { y: 42 }
注意
({ x = 10 } = {}); // x => x:x=10
({ y } = { y: 10 }); // y => y:y
console.log(x, y); // 10 10
四、函数参数解构
数组解构
function test([x, y]) {
console.log(x, y);
}
test([1, 2]); // 1, 2
test([1]); // 1 undefined
test([]); // undefined undefined
对象解构
function test({ x, y }) {
console.log(x, y);
}
test({ x: 1, y: 2 }); // 1, 2
test({ x: 1 }); // 1 undefined
test({}); // undefined undefined
默认参数
注意除了函数有默认值,解构参数也有默认值
function foo({ x = 10 } = {}, { y } = { y: 10 }) {
console.log(x, y);
}
foo() // 10 10
foo({},{}) // 10 undefined
foo({x:2},{y:3}) // 2 3
五、解构隐式转换
布尔值、number、boolean都会进行隐式转换
字符串转为类数组
const [a, b, c, d, e] = 'hello'; // 这里将字符串隐式转换成了类数组
console.log(a, b, c, d, e) // h e l l o
// 验证
let { length: len } = 'hello';
console.log(len); // 5
数值转换相应的包装类
let { toString: s } = 123;
console.log(s); // [Function: toString]
// 验证
console.log(s === Number.prototype.toString); // true
布尔值转换相应的包装类
let { toString: s } = false;
console.log(s); // [Function: toString]
// 验证
console.log(s === Boolean.prototype.toString); // true
undefined和null不能进行隐式转换
let { prop } = undefined;
console.log(prop); // 报错
let { prop } = null;
console.log(prop); // 报错
包装类其实就是JS底层经过加工的对象,方便隐式转换
六、书写规范
建议使用缩进增强代码可读性
let person = {
name: 'zs',
ageZhang: 50,
son: {
name: 'ls',
ageLi: 30,
son: {
name: 'ww',
ageWang: 18,
son: {
name: 'zl',
ageZhao: 0
}
}
}
}
// 不要这样写
let { son: { son: { son: { ageZhao }, ageWang }, ageLi }, ageZhang } = person;
console.log(ageZhao, ageWang, ageLi, ageZhang);
// 规范写法
let {
son: {
son: {
son: {
ageZhao
},
ageWang
},
ageLi
},
ageZhang
} = person;