es6--解构赋值

概述

结构赋值是对赋值运算符的扩展,他是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值

解构模型

  • 解构的源:解构赋值表达式的右边部分
  • 解构的目标:结构赋值表达式的左边部分

数组模型的解构(Array)

基本

let [a,b,c]=[1,2,3];
//a=1
//b=2
//c=3

可嵌套

let [a,[[b],c]]=[1,[[2],3]];
//a=1,b=2,c=3

可忽略

let [a, , b] = [1, 2, 3];
// a = 1
// b = 3

不完全解构(即等号左边的模式,只匹配一部分的等号右边的数组)

let[a=1,b]=[]; //a=1,b=undefined

剩余运算符

let [a, ...b] = [1, 2, 3];
//a = 1
//b = [2, 3]

解构默认值

let [a=2]=[undefined];

当解构模式有匹配结果,且匹配结果是undefined时,会触发默认值作为返回结果

ps:
ES6 内部使用严格相等运算符(=),判断一个位置是否有值。所以,如果一个数组成员不严格等于undefined==,默认值是不会生效的。

let [x = 1] = [undefined];
x // 1

let [x = 1] = [null];
x // null  //  null不严格等于undefined。
  • 默认值是表达式:若默认值是表达式,那么这个表达式是默惰性求值的,即只有在用到的时候,才会求值
function f(){
    console.log("aaa");
}

let [x=f()]=[1]; //1
  • 默认值可以引用解构赋值的其他变量,但该变量必须已经声明
let [a = 3, b = a] = [];     // a = 3, b = 3
let [a = 3, b = a] = [1];    // a = 1, b = 1
let [a = 3, b = a] = [1, 2]; // a = 1, b = 2

a 与 b 匹配结果为 undefined ,触发默认值:a = 3; b = a =3

a 正常解构赋值,匹配结果:a = 1,b 匹配结果 undefined ,触发默认值:b = a =1

a 与 b 正常解构赋值,匹配结果:a = 1,b = 2

右边不是数组

如果等号右边不是数组,或者严格来说不是可遍历的结构,那么将会报错

// 报错
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};

对象模型的解构(Object)

对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。

对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

如果变量名与属性名不一致,必须写成下面这样。

var { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"

let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'
let { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
foo // error: foo is not defined

上面代码中,foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo。

基本

let {foo,bar}={foo:'aaa',bar:'bbb'};
// foo='aaa'   bar='bbb'

let {baz:foo}={bar:'ddd'};
//foo='ddd'

可嵌套可忽略

let obj={p:['hello',{y:'word'}]};
let {p:[x,{y}]}=obj;
// x='hello'  y=word

let obj = {
  p: [
    'Hello',
    { y: 'World' }
  ]
};

let { p, p: [x, { y }] } = obj;
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]

不完全解构

let obj = {p: [{y: 'world'}] };
let {p: [{ y }, x ] } = obj;
// x = undefined
// y = 'world'

剩余运算符

let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40};
// a = 10
// b = 20
// rest = {c: 30, d: 40}

解构默认值

let {a = 10, b = 5} = {a: 3};
// a=3;b=5;
let {a: aa = 10, b: bb = 5} = {a: 3};
//aa=3;bb=5
var node = {
  loc: {
    start: {
      line: 1,
      column: 5
    }
  }
};

var { loc, loc: { start }, loc: { start: { line }} } = node;
line // 1
loc  // Object {start: Object}
start // Object {line: 1, column: 5}

上面代码有三次解构赋值,分别是对loc、start、line三个属性的解构赋值。注意,最后一次对line属性的解构赋值之中,只有line是变量,loc和start都是模式,不是变量。

let {foo} = {bar: 'baz'};
foo // undefined

如果解构失败,变量的值等于undefined。

// 报错
let {foo: {bar}} = {baz: 'baz'};

如果解构模式是嵌套的对象,而且子对象所在的父属性不存在,那么将会报错。

上面代码中,等号左边对象的foo属性,对应一个子对象。该子对象的bar属性,解构时会报错。原因很简单,因为foo这时等于undefined,再取子属性就会报错


如果要将一个已经声明的变量用于解构赋值,必须非常小心。

// 错误的写法
let x;
{x} = {x: 1};
// SyntaxError: syntax error

面代码的写法会报错,因为 JavaScript 引擎会将{x}理解成一个代码块,从而发生语法错误。只有不将大括号写在行首,避免 JavaScript 将其解释为代码块,才能解决这个问题。

// 正确的写法
let x;
({x} = {x: 1});

对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量。

let { log, sin, cos } = Math;

上面代码将Math对象的对数、正弦、余弦三个方法,赋值到对应的变量上,使用起来就会方便很多。


由于数组本质是特殊的对象,因此可以对数组进行对象属性的解构。

let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1
last // 3
字符串的解构赋值

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。

字符串等

在数组的解构中,解构的目标若为可遍历的对象,皆可进行解构赋值

let [a, b, c, d, e] = 'hello';
// a = 'h'
// b = 'e'
// c = 'l'
// d = 'l'
// e = 'o'

类似于数组的对象都有一个length的属性,因此号可以对这个属性解构赋值

let {length:len}="hello";
len //5
数值和布尔值的解构赋值

解构赋值时,如果等号右边是数值和布尔值,则会先转换为对象。

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

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

上面代码中,数值和布尔值的包装对象都有toString属性,因此变量s都能取到值。

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

let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
函数参数的解构赋值
function add([x, y]){
  return x + y;
}

add([1, 2]); // 3

函数add的参数表面上是一个数组,
但在传入参数的那一刻,
数组参数就被解构成变量x和y。
对于函数内部的代码来说,
它们能感受到的参数就是x和y。

使用默认值

function move({x = 0, y = 0} = {}) {
  return [x, y];
}

move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]

注意:

function move({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}

move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]

上面代码是为4函数move参数指定默认值,
而不是为变量x和y指定默认值,
所以会得到与之前一种写法不一样的结果


undefined会触发函数参数的默认值

[1,undefined,3].map((x='yes')=>x);
//[1,'yes',3]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值