JavaScript 学习笔记:ES6 新特性 — 解构赋值、展开语法、剩余参数
ES6
泛指
5.1
版以后的下一代
JS
标准。涵盖
ECMAScript 2015、ECMAScript 2016、ECMAScript 2017
。
其中
15
是正式版
16,17
只是在
15
基础上的补丁。
一、解构赋值
1、解构数组
1.1 语法
var arr = [1 , 2];
var [a, b] = arr;
console.info(a, b); // 1 2
1.2. 示例
1.2.1. 交换变量
js终于也支持这种语法了
var x = 1, y = 2;
[x, y] = [y, x];
console.info(x, y); // 2 1
1.2.2. 丢掉一部分变量
如果函数返回一个数组,外面有需要从数组中取元素来赋值,这个就方便了。
var [a, , , d] = [1, 2, 3, 4];
console.log(a); // 1
console.log(d); // 4
1.2.3. 默认值
// 有值直接取
var [a, b='B', c='C', d] = [1, 2, 3, 4];
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
console.log(d); // 4
// 无值用默认
var [a, b='B', c='C', d] = [1, , , 4];
console.log(a); // 1
console.log(b); // B
console.log(c); // C
console.log(d); // 4
// undefined 也当无值。但null不能触发默认值,因为null是一个值
var [a, b='B', c='C', d] = [1, undefined, undefined, 4];
console.log(a); // 1
console.log(b); // B
console.log(c); // C
console.log(d); // 4
2、解构对象
左边用key
当变量,接受右边对象中对应key
的值
2.1. 语法
2.1.1. 基本语法
- 解构并赋值给新变量
var obj = {a:1 , b:2};
var {a, b} = obj ; // 声明了a, b 两全局变量
console.info(a, b); // 1 2
- 用已有变量接收值
上面的语法有个缺陷,我们并不总是要创建新变量
,有时只是想用已有变量
,接收值。
var obj = {a:1, b:2, c:3};
var a, b, c;
( {a, b, c} = obj );
console.log(`a=${a}, b=${b}, c=${c}`); // a=1, b=2, c=3
- 用另一个对象接收
如果我们想将对象1的部分属性,复制给对象2,则还需要结合 2.1.4 的改名规则。
var obj1 = { a: 1, b: 2, c: 3 };
var obj2 = { a: 666, c: 999};
({a: obj2.a, c: obj2.c} = obj1);
console.log(obj2); // 输出:{ a: 1, c: 3 }
var sources = {a:1, b:2, c:3, d:4}; // 源
var {a, b, c} = {...sources};// 提取指定属性
var target = {a, b, c}; // 创建新对象
console.log(target); // 输出:{a: 1, b: 2, c: 3}
2.1.2. 多层嵌套对象解构
对象还包含对象。。。(听上去是一个悲伤的故事2333333)
var obj = {
a: '奔波儿灞' ,
b: '霸波尔奔',
npc:{ name : '龙王'}
};
var {a , b, npc:{name} } = obj;
console.info(a); // 奔波儿灞
console.info(b); // 霸波尔奔
console.info(npc); //npc is not defined
console.info(name); //龙王
2.1.3. 混合嵌套
对象跟数组混着套来套去。
var obj = {
a: '奔波儿灞' ,
b: '霸波尔奔',
npc: [1, 2, 3, 4]
};
var {a , b, npc:[n1, n2, n3, n4] } = obj;
console.info(a); // 奔波儿灞
console.info(b); // 霸波尔奔
console.info(n1); // 1
console.info(n2); // 2
console.info(n3); // 3
console.info(n4); // 4
2.1.4. 声明新变量 (换名字)
当原对象的key
名字不符合我们要求时,可以如下操作,实现改名。
解构后得到新变量 npc1、npc2
。
var obj = {a: '奔波儿灞' , b: '霸波尔奔'};
var {a: npc1, b: npc2} = obj ; // 从 obj.a 取值赋给 npc1, 从 obj.b 取值赋给 npc2
console.info(npc1, npc2); // 奔波儿灞 霸波尔奔
2.4. 函数参数解构
function foo({npc, npcLoc, hp }){
console.log(npc, npcLoc, hp);
}
foo({npc:'奔波儿灞', npcLoc:{ x: 0, y: 0}, hp:99 });
将数组展开成单个参数,与Function.prototype.apply()效果相同 。
((a,b,c)=>{
console.log(a,b,c);
})(...['龙王','奔波儿灞','霸波尔奔']);
((a,b,c)=>{
console.log(a,b,c);
}).apply(null, ['龙王','奔波儿灞','霸波尔奔']);
2.4.1 参数默认值
- 基本类型
function test(str = "大家好,我是笨笨,笨笨的笨,笨笨的笨,谢谢!", n = 123){
console.log(str);
console.log(n);
}
- 对象
function foo(options = {}){
let {npc = '霸波尔奔', npcLoc = { x: 9527, y: 2046 }, hp = 10000} = options;
console.log(npc, npcLoc, hp);
}
foo(); // 霸波尔奔 {x: 9527, y: 2046} 10000
foo({npc:'奔波儿灞', npcLoc:{ x: 0, y: 0}}); // 奔波儿灞 {x: 0, y: 0} 10000
- 对象(简写)
function foo({npc = '霸波尔奔', npcLoc = { x: 9527, y: 2046 }, hp = 10000} = {}){
console.log(npc, npcLoc, hp);
}
3. 属性简写
字面量中,key
和 value
相同时时可以简写。(以后声明方法时经常用。)
var a = 1, b = 2;
var obj = { a : a, b : b}; // 完整写法
var obj1 = {a, b}; // 简写
JSON.stringify(obj,null,0) === JSON.stringify(obj1,null,0); // true
当然函数也可以当属性,所以:
var obj = {
fun(){
console.log(666);
}
};
obj.fun(); // 666
二、展开语法
let [... arr] = [ 1,2,3,4 ];
// 接收时的效果是收集进数组。
let [a,b,c,d] = [... arr];
// 赋值时的效果是展开成多个。
函数调用
// 为了演示先定义个函数
function foo(a,b,c){
console.info('第一个参数: ' + a);
console.info('第二个参数: ' + b);
console.info('第三个参数: ' + c);
}
// 这是我们为它准备的实参
var arr = ['666','999','9527'];
// 在以前是这样实现的
foo.apply(null, arr);
// 利用展开语法的写法
foo(...arr);
new新对象时
显然 apply
虽好,但在new
新对象的时候就没那么好用了。有了展开语法可以结局这个尴尬
- 数组去重
var result = [...new Set([1,1,2,2,3,3,4,4])];
console.info(result);// [1, 2, 3, 4]
// 分解步骤
var arr = [1,1,2,2,3,3,4,4];
var myset = new Set(arr);// 实际去重是利用集合元素不重复的特性实现的
var result = [...myset];
console.info(result);// [1, 2, 3, 4]
创建时间对象
new Date(...[2019,10,05]);
new Date(..."2019-10-05".split("-"));
new Date("2019-10-05");
字面量数组
值得注意的是这种展开是一种浅复制(只遍历一层),如果多为嵌套就要小心了。不然会无意间修改到原始对象。
// 直接展开来用
var a = [1,2,3], b = [4,5,6];
var arr = [...a, ...b];
console.info(arr);// [1, 2, 3, 4, 5, 6]
// 还可以反反复复用
var arr = [...a, ...b, ...a];
console.info(arr);// [1, 2, 3, 4, 5, 6, 1, 2, 3]
字面量对象
在数组或函数参数中使用展开语法时, 该语法只能用于 可迭代对象。
下面的例子很像 jQuery
的 $.extend 合并对象
var obj1 = { 'year': '2019', 'month': '10' };
var obj2 = { 'year': '2020', 'day': '05' };
var obj3 = {...obj1, ...obj2};
// year 有两个,后面的替换了前面的。 month 和 day 只有一个,都直接留下了。
console.info(obj3);// {year: "2020", month: "10", day: "05"}
// 浅复制没问题,但不支持深度复制。
obj3.year = "2046";
obj3.month = "12";
obj3.day = '31';
console.info(obj3);// {year: "2046", month: "12", day: "31"}
console.info(obj1);// {year: "2019", month: "10"}
console.info(obj2);// {year: "2020", day: "05"}
三、组合使用
数组套对象
var [name, { msg}] = ['笨笨', { msg: '大家好,我是笨笨,笨笨的笨,笨笨的笨,谢谢!' }];
console.log(`name: "${name}", msg: "${msg}"`);
// name: "笨笨", msg: "大家好,我是笨笨,笨笨的笨,笨笨的笨,谢谢!"
剩余参数
其余参数封装进一个真
数组里,这个是针对 arguments 说的。
// 为了演示先定义个函数
function foo(a,b,c,...arr){
console.info('第一个参数: ' + a);
console.info('第二个参数: ' + b);
console.info('第三个参数: ' + c);
console.info('其余参数封装进一个真数组里' + Array.isArray(arr) + ': ' + arr);
}
foo(1,2,3,4,5,6,7,8,9);
/*
第一个参数: 1
第二个参数: 2
第三个参数: 3
其余参数封装进一个真数组里true: 4,5,6,7,8,9
*/
Object 对象映射
将源对象
中指定key
的value
赋值给目标对象
的指定key
/**
* 对象映射
*
* @param {Object} source 源对象
* @param {Array} keys 源对象的key
* @param {Object} dist 目标对象
* @param {Array} keys2 目标对象的key
*/
function objMapping(source, keys, dist = {}, keys2 = keys){
return keys.reduce((a,c,i) => Object.assign(a, {[keys2[i]]:source[c]}) , dist);
}
objMapping({a:1, b:2, c:3}, ["a", "b"], {aa:11, bb:22, cc: 33});
// {aa: 11, bb: 22, cc: 33, a: 1, b: 2}
objMapping({a:1, b:2, c:3}, ["a", "b"], {aa:11, bb:22, cc: 33}, ["aa", "cc"]);
// {aa: 1, bb: 22, cc: 2}
参考资料
解构赋值 Destructuring_assignment
展开语法 Spread syntax
剩余参数 Rest_parameters
阮一峰 Blog:变量的解构赋值