数组的解构赋值
以前:
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");