Javascript ES6/ES2015
,其中许多特性其实是为了简化代码。解构运算符、扩展运算符、rest运算符就是其中很好的特性,它们可以通过减少赋值语句的使用,或者减少通过下标访问数组或对象的方式,使代码更加简洁优雅,可读性更佳。
解构
解构的作用是可以快速取得数组或对象当中的元素或属性,而无需使用arr[index]
或者obj[key]
等传统方式进行赋值
数组解构赋值:
let arr = ['字符串', 11, true]; // 传统方式: var a = arr[0], b = arr[1], c = arr[2]; // 解构赋值,效果相同 let [a, b, c] = arr;
嵌套数组解构:
let arr = [['字符串', 11, true], [1, 2, 3], [4, 5, 6]]; let [[a, b, c], d, e] = arr; // 结果:a == '字符串',b == 11,c == true,d == [1, 2, 3], e == [4, 5, 6]
函数传参解构:
let arr = ['字符串', 11, true]; ;(function ([a, b, c]) { // 结果:a == '字符串',b == 11,c == true })(arr);
for循环解构:
let arr = [ ['字符串', 11, true], [1, 2, 3], [4, 5, 6] ]; for (let [a, b, c] of arr) { // 字符串 11 true // 1 2 3 // 4 5 6 }
对象赋值解构:
let obj = { name: '名字', age: 22, eat: { food1: '苹果', food2: '香蕉' } }; let {name, age, eat} = obj; // 结果:name == '名字',age == 22, eat == [object Object] let {food1, food2} = eat; // 结果:food1 == '苹果',food2 == '香蕉'
对象传参解构:
let obj = { name: '名字', age: 22, eat: { food1: '苹果', food2: '香蕉' } }; ;(function ({name, age, eat}) { // 结果:name == '名字',age == 22, eat == [object Object] })(obj);
变量名与对象属性名不一致解构(指定别名):
let obj = { name: '名字', age: 22 }; let {name: n, age: a} = obj; // 结果:n == '名字',a == 22
对象嵌套解构:
let obj = { name: '名字', age: 22, eat: { food1: '苹果', food2: '香蕉' } }; let { name, age, eat: {food1, food2} } = obj; // 结果:name == '名字',age == 22, food1 = '苹果',food2 == '香蕉'(附注:age不存在)
对象嵌套重名解构:
let obj = { name: '名字1', age: 22, friend: { name: '名字2', age: 20 } }; let { name, age, friend: {name: n, age: a} } = obj; // 结果:name == '名字1',age == 22, n == '名字2',a == 20(附注:friend不存在)
循环解构对象:
let arr = [ {name: 'zs', age: 20}, {name: 'ls', age: 21}, {name: 'ww', age: 22} ]; for (let {name, age} of arr) { // zs 20 // ls 21 // ww 22 }
解构特殊场景:
// 字符串处理 let str = 'abc'; let [a, b, c, d] = str; // 结果:a == 'a', b == 'b', c == 'c', d == 'undefined' // 值互换 let x = 1, y = 2; [x, y] = [y, x]; // 不能let定义,因为已存在 // 结果 x == 2, y == 1; //对任意深度的嵌套数组进行解构 var [foo, [ [bar], baz] ] = [1, [ [2], 3] ]; console.log(foo); // 1 console.log(bar); // 2 console.log(baz); // 3 // 忽略尾随元素 let [first] = [1, 2, 3, 4]; console.log(first); // 1 //忽略部分元素 let [, second, , forth] = [1, 2, 3, 4]; console.log(second); // 2 console.log(forth); // 4 // 没有声明的赋值 ({a, b} = {a:'foo', b:12, c:'bar'}); // 注意此处,需要用括号括起来,因为javascript通常会以{起始的语句作为一个代码块。 // 对象展开(属性值覆盖) let default = {food:'spicy', price:'$', drink:'coko'}; let search = {...default, food:'rich'}; console.log(search); // {food:'rich', price:'$', drink:'coko'} // 声明给出默认值 let obj = {a: 1, b: 2, c: 3}; let {a, b, c, d = 4} = obj; // a,b,c,d分别等于1,2,3,4 // 对象展开(附注:typescript语法)它只包含自身的可枚举的属性。 并且会丢失展开对象的方法: class C = {p:12, m(){}}; let c = new C(); let clone = {...c}; console.log(clone.p); // 12 console.log(clone.m); // error! // 指定类型(附注:typescript语法) let {a, b} : {a:string, b:number} = o; // 指定默认值(附注:typescript语法) (即使b为undefined,obj的属性a, b也都会有值) function keepWhole(obj: { a: string, b?: number }) { let { a, b = 1001 } = obj; };
拓展运算符
扩展运算符用三个点号 ...
表示,功能是把数组或类数组对象展开成一系列用逗号隔开的值
var arr = [1, 2, 3]; var fn = function (a, b, c) { // 结果:a == 1, b == 2, c == 3; } // 传统方式: fn(arr[0], arr[1], arr[2]); // 拓展运算符方式 fn(...arr);
特殊应用场景:
var arr = [1, 2, 3]; // 数组深度拷贝 var arr2 = arr; // arr2 === arr,指向同一引用 var arr3 = [...arr]; // arr3 !== arr,非指向同一引用 // 数组插入 var arr4 = [...arr, 4, 5, 6]; // 结果:[1, 2, 3, 4, 5, 6] // 字符串转数组 var str = 'abcd'; var arr5 = [...str]; // 结果:['a', 'b', 'c', 'd']
rest运算符
rest运算符也是三个点号,不过其功能与扩展运算符恰好相反,把逗号隔开的值序列组合成一个数组
//主要用于不定参数,所以ES6开始可以不再使用arguments对象
;(function (...args) { for (let el of args) { // 输出:1 2 3 4 } })(1, 2, 3, 4); ;(function (a, ...args) { // a === 1 // args == [2, 3, 4] })(1, 2, 3, 4);
rest运算符配合解构使用:
let [a, ...args] = [1, 2, 3, 4]; // a === 1 // args == [2, 3, 4]
小结:
=
表达式是典型的赋值形式,函数传参和for
循环的变量都是特殊形式的赋值。解构的原理是赋值的两边具有相同的结构,就可以正确取出数组或对象里面的元素或属性值,省略了使用下标逐个赋值的麻烦。
对于三个点号...
,放在形参或者等号左边为rest
运算符; 放在实参或者等号右边为spread
运算符(扩展运算符),或者说,放在被赋值一方为rest运算符,放在赋值一方为扩展运算符。
总结:
1、在等号赋值或for
循环中,如果需要从数组或对象中取值,尽量使用解构。
2、在自定义函数时,如果调用者传来的是数组或对象,形参(定义)尽量使用解构方式,优先使用对象解构,其次是数组解构。代码可读性会很好。
3、在调用第三方函数的时候,如果该函数接受多个参数,并且你要传入的实参(调用)为数组,则使用扩展运算符。可以避免使用下标形式传入参数。也可以避免很多人习惯的使用apply
方法传入数组。
4、rest
运算符使用场景应该稍少一些,主要是处理不定数量参数,可以避免arguments对象的使用。
近期评论