【ES6】变量的解构赋值(超详细)

数组的解构赋值

以前:

let a = 1;
let b = 2;
let c = 3;

ES6:

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

数组嵌套解构例子

let [foo,[[bar],baz]] = [1,[[2],3]]

let [,,third] = ["foo","bar","baz"]
third//"baz"

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

let [head, ...tail] = [1,2,3,4]
head//[1]
tail//[2,3,4] 

let [x,y,...z] = ['a']
x//"a"
y//undefined
z//[]

如果解构不成功,则会赋值undefined

let [foo] = [];
let [bar,foo] = [1];
//这两个例子都属于解构不成功,foo的值都等于undefined

不完全解构(等号左边的只匹配一部分的等号右边的数组)=>可以解构成功

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

let [a,[b],d] = [1,[2,3],4]
a//1
b//2
d//4 

如果等号的右边不是数组,或是不可遍历的结构,则会报错
【原因:右边的值转为对象后不具备Iterator 接口(例前五个表达式),要么本身就不具备Iterator接口(最后一个表达式)】

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

对于Set结构,也可以使用数组的解构赋值

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

tip:只要某种数据结构具有Iterator接口,都可以采用数组形式进行解构赋值

解构赋值允许指定默认值
(1)默认值是一个数组

let [foo = true] = [];
foo//true

let[x, y = 'b'] = ['a']
//x='a',y='b'
let [x,y='b'] = ['a',undefined]
//x='a',y='b'

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

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

let [x = 1] = [null]
x//null
//如果一个数组成员是null,null不严格等于undefined,默认值不会生效

(2)默认值是一个表达式
当解构赋值指定的默认值是一个表达式,那么这个表达式是具有惰性的,即只有调用到了的时候才会求值

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

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

//因为x已经有赋值为1了,所以并没有去调用到函数f()
//上面代码等价于下面所示代码

let x;
if([1][0] === undefined){
	x = f();
}else{
	x = [1][0]
}

//[1][0]的意思是var a = [1],取a[0]的值,
//即[1][0] = a[0]

(3)默认值可以引用解构赋值的其他变量,但该变量必须已经声明。

let [x = 1, y = x] = []; //x=1,y=1
let [x = 1, y = x] = [2]; //x=2,y=2
let [x = 1, y = x] = [1,2] //x=1,y=2
let [x = y, y = 1] = []; //报错,因x用y做默认值时,y还未声明

对象的解构赋值

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

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

对象的解构赋值与数组的解构赋值不同:
数组的元素是按次序排序的,变量的取值由它的位置决定
对象的属性没有次序,变量必须与属性同名,才能取到值,如果没有同名则解构失败,变量的值为undefined

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

let { 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

1.对象的解构赋值可以将现有对象的方法赋值到某个变量

let { log, sin cos } = Math;
//将Math对象的方法赋值到对应的log sin cos 的变量上去
const { log } = console;
log("hello")
//将console方法赋值到log变量

2.与数组一样,解构也可以用于嵌套结构的对象。

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"}]

另外一个例子:

const node = {
	loc: {
		start: {
			line:1,
			column:5
		}
	}
};

let { 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是模式,不是变量

3.对象的解构赋值可以取到继承的属性

const obj1 = {};
const obj2 = { foo: 'bar' };
Object.setPrototypeOf(obj1,obj2);
//对象obj1的原型对象是obj2,foo属性不是obj1本身的属性,而是继承obj2得来的

const { foo } = obj1;
foo//"bar"
//Object.setPrototypeOf(),为现有对象设置原型,返回一个新对象
//接收两个参数:第一个是现有对象,第二是原型对象。

对象的解构赋值指定默认值

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 well' } = {};
msg//"Something went well"

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

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

var {x=3} = {x: null};
x//null
//因为null与undefined不严格相等,所以不是个有效的赋值,导致默认值3不会生效

字符串的解构赋值

字符串被转换成一个类似数组的对象

const [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 === Boolean.prototype.toString //true

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

//报错
let { prop: x } = undefined;
let { prop: y } = null;

函数参数的解构赋值

function add ([x,y]){
		return x+y;
	}
add([1,2]);//3
[[1,2],[3,4]].map(([a,b]) => a+b );
//[3,7]

函数参数的解构使用默认值

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]

//函数move的参数是一个对象,通过这个对象进行解构,得到变量x和y的值,若解构失败,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]

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

[1,undefined,3].map((x = 'yes') => x);
//[1,'yes',3]

解构赋值的用途
1.交换变量的值,写法简洁,易读

let x = 1;
let y = 2;

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

2.当函数返回多个值并存入一个数组或对象时,利用解构赋值可从数组或对象取出值

// 返回一个数组

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

// 返回一个对象

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

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

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

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

4.提取JSON数据(可快速提取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.函数参数的默认值

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");
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值