JavaScript简明教程-变量的解构赋值

634 阅读4分钟

基本概念

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring),解构写法属于“模式匹配”,

数组解构赋值

  • 如果等号两边的模式相同,左边的变量就会被赋予对应的值,这就是完全解构
let [foo, [[bar], baz]] = [1, [[2], 3]]; // foo:1, bar:2, baz:3
let [head, ...tail] = [1, 2, 3, 4]; // head:1, tail: [2, 3, 4]
  • 如果值可以解构,但是不能正常解构,变量的值就是undefined
let [foo] = [];
foo // undefined
  • 如果值不可被解构,对应值是不可遍历的,将会报错
let [foo] = 1; // false, NaN, undefined, null, {}均不可遍历
// Uncaught TypeError: 1 is not iterable
  • 如果等号左边的模式,只匹配一部分右边模式,这就是不完全解构
let [x, y] = [1, 2, 3]; // x:1, y:2
  • 解构赋值允许指定默认值,默认值只会在对应模式值严格等于undefined 才会生效
let [x = 1] = [undefined];
x // 1

let [x = 1] = [null];
x // null
  • 默认值如果是其他变量,这个变量必须先声明
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = [];     // ReferenceError: y is not defined

对象的解构赋值

对象的结构赋值相当于将目标对象自身所有可遍历但尚未被读取的属性,分配到指定的对象上面

  • 对象的解构赋值与数组解构概念相同,但在具体实现上,是先找到同名属性,然后再赋给对应的变量
let { foo: baz } = { foo: 'aaa', bar: 'bbb' }; // baz: 'aaa', foo是模式,baz才是需要匹配的值
let { baz } = { foo: "aaa", bar: "bbb" }; // undefined 没有相关匹配
  • 如果属性和变量同名,可以使用简写
let { bar, foo } = { foo: "aaa", bar: "bbb" }; // bar:'bbb', foo:'aaa'
let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" }; // 上面是这个的简写
  • 如果属性名和变量名不一致,不可简写
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
  • 注意匹配模式与变量的区别
let {userInfo: {firstName, lastName}, code} = {code:'000', userInfo: {firstName:'rede', lastName:'li'}}; // 模拟处理接口返回,此时定义的变量为firstName, lastName和code,userInfo则是匹配模式,不是变量
let {userInfo, code} = {code:'000', userInfo: {firstName:'rede', lastName:'li'}}; // 此处userInfo是变量
  • 对象解构也可以给定默认值,默认值生效条件依然是值严格等于undefined
let { message: msg = 'Something went wrong' } = {}; // msg为默认值,默认值生效的条件也是为空或者undefined
  • 如果解构失败,变量值等于undefined

  • 进行解构如果是嵌套对象,注意对应父级要存在

let {foo: {bar}} = {baz: 'baz'}; // Cannot destructure property `bar` of 'undefined' or 'null'
  • 进行解构最好在定义变量时进行,避免先定义再进行解构
let x;
{x} = {x: 1}; //  Unexpected token =(未知的语法错误)
...
let x;
({x} = {x: 1}); // x正常赋值,但是这种写法吧个人感觉不友好,会尽量避免少用
  • 解构赋值,可以很方便的从对象中获取方法
let { log, sin, cos } = Math;
  • 避免不必要的错误,模式中禁止使用圆括号
  • 扩展运算符的解构赋值,必须是最后一个参数
let { x, ...y, z } = { x: 1, y: 2, a: 3, b: 4 };
// Uncaught SyntaxError: Rest element must be last element
  • 扩展运算符的解构赋值,不能复制继承自原型对象的属性
let o1 = { a: 1 };
let o2 = { b: 2 };
Object.setPrototypeOf(o2, o1);
let { ...o3 } = o2;
o3; // {b: 2}
o3.a; // undefined 

字符串解构

和数组解构操作类似,对字符串进行解构

数字和布尔值解构

进行解构时会把要解构的数字或布尔值转为对象,在进行解构。。。不过解构这些值有何意义

js最为人诟病的地方就是进行变量操作时,变量数据类型不确定,会进行隐式转换,我们在开发时应该要避免这种情况,只对确定的数据进行解构,在操作前要对数据进行类型校验,避免不确定的默认行为

函数参数的解构赋值

函数参数可以进行数组解构和对象解构

  • 支持默认值的写法
// 这是指定参数x,y的解构默认值
function move({x = 0, y = 0}) {
  return [x, y];
}
move({x: 3}); // [3, 0]
move({}); // [0, 0]
// 这是指定函数参数的默认值
function move({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]