02.ES6之变量解构赋值

一、数组的解构赋值

1.从数组和对象中取值,对变量进行赋值,被称为解构。

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

上面代码,从数组中取值,按照对应位置对变量进行赋值,就是解构赋值。

2.如果解构不成功,变量的值就为undefined,如下:

let f = [];
f // undefined

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

let [x,y,...z] = ['aa'];
x //  'aa'
y // undefined
...z // []

3.等号左边的模式只匹配一部分的等号右边的数组,为不完全解构,可以解构成功。

let [q,a,z] = [1,2,3,4];
q // 1
a // 2
z // 3

let [a,[b],c] = [11,[22,33],44];
a // 11
b // 22
c // 44

4.如果等号右边的值不是数组或不是可遍历的解构,将会报错,比如:

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

5.set解构也可以进行解构赋值

let [x,y,z] = new Set([a,b,c]);
y // b

6.解构赋值允许指定默认值

注:只有当一个数组成员严格等于undefined时,默认值才生效(未定义或定义为undefined)

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

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

let [a,b = true] = [1,null];
a // 1
b // null

如果默认值是一个表达式,那么表达式是惰性求值的,只有用到的时候,才会求值。

function f() {
  console.log('aaa');
}

let [x = f()] = [1];

上面代码中,因为x能取到值,所以不会去执行f().

默认值也会引用解构赋值的其他变量,但变量必须已经声明。

let [x=1.y=x] = [];
x // 1
y // 1

let [x=1.y=x] = [2];
x // 2
y // 2

let [x=1.y=x] = [2,3];
x // 2
y // 3

let [x=y y=1] = [];
x //  ReferenceError: y is not defined

二、对象的解构赋值

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

let {a,b} = {a:'qqq',b:'zzz'};
a // 'qqq'
b // 'zzz'

let {a,b} = {b:'qqq',a:'zzz'};
a // 'zzz'
b // 'qqq'

let {c} = {b:'qqq',a:'zzz'};
c // undefined

上面的代码第一个和第二个例子想要表达的是,由于等号右边的变量和左边的对象属性同名,所以次序一致或不一致,对取值没有影响;第三个例子是说,右边变量里没有对应的同名属性,取不到值,最后为undefined

2.如果变量名和属性名不一致,就必须写成这样:

let {foo:baz} = {foo:'aaa'};
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

3.解构也可以用于嵌套结构的对象

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

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

上面代码中,p为模式,而不是变量;要想获得变量p,则可以这样写:

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

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

数组和对象嵌套的解构赋值可以这样:

let obj = {};
let arr = [];

({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });

obj // {prop:123}
arr // [true]

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

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

//主要原因是:foo这时等于undefined ,再取子属性就会报错

4.对象的解构也可以指定默认值

var {x = 3} = {};
x // 3

var {x, y = 5} = {x: 1};
x // 1
y // 5

var {x: y = 3} = {};
y // 3

var {x: y = 3} = {x: 5};
y // 5

var { message: msg = 'Something went wrong' } = {};
msg // "Something went wrong"

默认值生效的条件是,对象的属性值严格等于undefined

var {x = 3} = {x: undefined};
x // 3

var {x = 3} = {x: null};
x // null

5.如果一个已经声明的变量用于解构赋值,必须不能使{}置于行首,即外边需要()包裹起来

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


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

6.数组本身是特殊的对象,可以对数组进行对象属性的解构

let arr = [1,2,3,4];
let {0:first,3:middle,[arr.length-1]:last} = arr;
first  // 1
middle // 4
last   // 4

三、字符串的解构赋值

1.字符串也可以进行解构赋值 因为此时字符串被转换成类似数组的对象

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

2.可以对数组的length属性进行赋值

let {length:len} = 'hello';
len  // 5

四、数值和布尔值的解构赋值

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

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

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

解构赋值的规则是:只要等号右边的值不是对象和数组,就先将其转为对象。但undefined和null除外。

五、函数参数的解构赋值

1.比如下边这个例子:

function add([x, y]){
  return x + y;
}

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

虽然函数的参数是一个数组,但在传入参数的那一刻,数组参数就被解构成变量x和 y。

2.还有下边这个例子:

[[1, 2], [3, 4]].map(([a, b]) => a + b);
// [ 3, 7 ]

map函数参数是数组里的a和b,进行map的数组是二维数组,name里边的两个一位数组分别执行a+b。

3.函数参数解构也可以使用默认值,看下边这个例子:

(为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]

函数参数是个对象,通过对象进行解构,若解构失败,则用默认值。

下边这个例子之所以与前一个不一样,是因为这个是为函数的参数指定默认值,而上边的是为x,y变量指定默认值。

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]

六、解构赋值中不能使用圆括号的情况

1.变量声明语句,模式不能使用圆括号

// 全部报错
let [(a)] = [1];

let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};

let { o: ({ p: p }) } = { o: { p: 2 } };

2.函数参数也属于变量声明,也不能有圆括号

// 报错
function f([(z)]) { return z; }
// 报错
function f([z,(x)]) { return x; }

3.赋值语句中,将整个模式放在圆括号中,也会报错

// 全部报错
({ p: a }) = { p: 42 };
([a]) = [5];

4.赋值语句中,将一部分模式放在圆括号中,也会报错

// 报错
[({ p: a }), { x: c }] = [{}, {}];

七、可以使用圆括号的情况

只有一种:赋值语句的非模式部分可以使用圆括号。

[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确

上面三行语句都可以正确执行,因为首先它们都是赋值语句,而不是声明语句;其次它们的圆括号都不属于模式的一部分。第一行语句中,模式是取数组的第一个成员,跟圆括号无关;第二行语句中,模式是p,而不是d;第三行语句与第一行语句的性质一致。

八、变量的解构赋值的用处

1.交换变量的值

let x = 1;
let y = 2;

[x, y] = [y, x];

2.从函数返回多个值

// 返回一个数组

function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();


// 返回一个对象

function example() {
  return {
    foo: 1,
    bar: 2
  };
}
let { foo, bar } = example();

3.函数参数的定义

解构赋值可以方便的将一组参数与变量名对应起来

// 参数是一组有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3]);

// 参数是一组无次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});

4.提取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]

5.函数参数的默认值

指定参数的默认值,就会避免再在函数内部写var foo = config.foo || 'default foo';这样的语句。

jQuery.ajax = function (url, {
  async = true,
  beforeSend = function () {},
  cache = true,
  complete = function () {},
  crossDomain = false,
  global = true,
  // ... more config
} = {}) {
  // ... do stuff
};

6.遍历Map解构

const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');

for (let [key, value] of map) {
  console.log(key + " is " + value);
}
// first is hello
// second is world

如果只想获取键名或键值,可以这样写:

// 获取键名
for (let [key] of map) {
  // ...
}

// 获取键值
for (let [,value] of map) {
  // ...
}

7.输入模块的指定方法

const { SourceMapConsumer, SourceNode } = require("source-map");

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值