让人爱不释手的 JS 扩展操作符13种写法

开发 前端
扩展操作符给我最大的印象就是,这玩意还挺方便的,然而最近写代码的时候经常性的遇到需要使用扩展操作符的场景,所以我干脆在网上找了些资料,把平时常见的应用场景给罗列了下,发现这个操作符是真的强大,有多强大?来看看下面这些用法吧。

[[377080]]

 我相信你一定或多或少的接触或使用过 JS 中的扩展操作符(Spread Operator),在基本形式中,扩展操作符看起来像三个点,比如如下这样:

  1. [...arr] 

而实际上,它也就是这么用的,但是如果事情有这么简单,就不用我在这里写了。扩展操作符给我最大的印象就是,这玩意还挺方便的,然而最近写代码的时候经常性的遇到需要使用扩展操作符的场景,所以我干脆在网上找了些资料,把平时常见的应用场景给罗列了下,发现这个操作符是真的强大,有多强大?来看看下面这些用法吧。

1. 字符串转数组

字符串转数组最普遍的做法是这样:

  1. let str = 'hello' 
  2. let arr = str.split(''
  3. console.log(arr)  // ['h''e''l''l''o'

而使用了扩展操作符后可以这样:

  1. let str = 'hello' 
  2. let arr = [...str] 
  3. console.log(arr)  // ['h''e''l''l''o'

2. 将类数组转换为数组

在 JS 中有一种数据结构叫做 NodeList,它和数组很相似,也被叫做“类数组”,类数组是什么?在 MDN 中是这么定义它的:

  • “类数组:拥有一个 length 属性和若干索引属性的任意对象。

类数组有哪些呢?以下这些可以看成是类数组:

  • NodeList:document.querySelectorAll() 返回的对象;
  • HTMLCollection:document.getElementsByTagName() 返回的对象;
  • Arguments:函数里的参数对象;

类数组没有数组的一些方法比如 push、map 等,所以经常需要将它们转成数组,而通常我们是这么转化的:

  1. let nodeList = document.querySelectorAll('div'
  2. console.log(nodeList instanceof NodeList)  // true 
  3.  
  4. let arr = Array.apply(null, nodeList) 
  5. console.log(arr instanceof Array)  // true 
  6.  
  7. // 或者 
  8. let arr2 = [].slice.call(nodeList) 
  9. console.log(arr2 instanceof Array)  // true 
  10.  
  11. // 又或者 
  12. let arr3 = Array.from(nodeList) 
  13. console.log(arr3 instanceof Array)  // true 

而有了扩展操作符可以这么做:

  1. let nodeList = document.querySelectorAll('div'
  2. let arr = [...nodeList] 
  3. console.log(arr instanceof Array)  // true 

3. 向数组中添加项

往数组中添加几项通常这样操作:

  1. let arr = [5] 
  2.  
  3. // 从头部添加 
  4. arr.unshift(1, 2) 
  5. console.log(arr)  // [1, 2, 5] 
  6.  
  7. // 从尾部添加 
  8. arr.push(6, 7) 
  9. console.log(arr)  // [1,2, 5, 6, 7] 
  10.  
  11. // 从任意位置添加 
  12. arr.splice(2, 0, 3, 4) 
  13. console.log(arr)  // [1,2, 3, 4, 5, 6, 7] 

使用扩展操作符后:

  1. let arr = [3, 4] 
  2. arr = [1, 2, ...arr, 5, 6] 
  3. console.log(arr)  // [1, 2, 3, 4, 5, 6] 

4. 拷贝数组和对象

通常拷贝一个数组,可以这么做:

  1. let arr = [1, 3, 5, 7] 
  2. let arr2 = arr.concat() 
  3.  
  4. // 或者 
  5. let arr3 = arr.slice() 
  6. arr[0] = 2 
  7. console.log(arr)   // [2, 3, 5, 7] 
  8. console.log(arr2)  // [1, 3, 5, 7] 
  9. console.log(arr3)  // [1, 3, 5, 7] 

但是有了扩展操作符,拷贝数组就能写得很简单:

  1. let arr = [1, 3, 5, 7] 
  2. let arr2 = [...arr] 
  3. arr[0] = 2 
  4. console.log(arr2)  // [1, 3, 5, 7] 

同样的,扩展操作符还能拷贝对象。拷贝对象的通常做法:

  1. let person = { name'布兰', age: 12} 
  2. let p2 = Object.assign({}, person) 
  3. person.age = 20 
  4. console.log(person)  // { name'布兰', age: 20 } 
  5. console.log(p2)      // { name'布兰', age: 12 } 

有了扩展操作符,拷贝一个对象就相当方便了:

  1. let person = { name'布兰', age: 12 } 
  2. let p2 = {...person} 
  3. person.age = 20 
  4. console.log(person)  // { name'布兰', age: 20 } 
  5. console.log(p2)      // { name'布兰', age: 12 } 
  6.  
  7. // 甚至还可以这么写 
  8. let {...p3} = person 
  • “注意:扩展操作符只能深拷贝结构为一层的对象,如果对象是两层的结构,那么使用扩展操作符拷贝会是浅拷贝。

5. 合并数组或对象

数组合并通常是这么做的:

  1. let arr1 = [1, 3, 5] 
  2. let arr2 = [2, 4, 6] 
  3. let arr3 = arr1.concat( arr2 ) 
  4. console.log(arr3)  // [1, 3, 5, 2, 4, 6] 

使用扩展操作符后,可以这么写:

  1. let arr1 = [1, 3, 5] 
  2. let arr2 = [2, 4, 6] 
  3. let arr3 = [...arr1, ...arr2] 
  4. console.log(arr3)  // [1, 3, 5, 2, 4, 6] 

对了,它除了能合并数组外还能合并对象呢。合并对象,通常的做法是:

  1. let p1 = { name'布兰' } 
  2. let p2 = { age: 12 } 
  3. let p3 = Object.assign({}, p1, p2) 
  4. console.log(p3)  // { name'布兰', age: 12} 

用扩展操作符合并对象:

  1. let p1 = { name'布兰' } 
  2. let p2 = { age: 12 } 
  3. let p3 = { ...p1, ...p2 } 
  4. console.log(p3)  // { name'布兰', age: 12} 

6. 解构对象

经常我们给对象设置参数的时候会这么做:

  1. let person = { 
  2.     name'布兰'
  3.     age: 12, 
  4.     sex: 'male' 
  5. let name = person.name 
  6. let age = person.age 
  7. let sex = person.sex 

而有了扩展操作符,我们就可以这么写,不过其实如下这种写法并不是扩展操作符的写法🤣,而是剩余操作符的写法,虽然写出来后看起来差不多,但就在操作对象这一点上,基本上可以认为它和扩展操作符是相反的操作,扩展操作符是用来展开对象的属性到多个变量上,而剩余操作符是用来把多个参数凝聚到一个变量上。

  1. let person = { 
  2.     name'布兰'
  3.     age: 12, 
  4.     sex: 'male' 
  5. let { name, ...reset } = person 
  6. console.log(name)   // '布兰' 
  7. console.log(reset)  // { age: 12, sex: 'male' } 

7. 给对象添加属性

给对象加属性通常这样加:

  1. let person = { name'布兰' } 
  2. person.age = 12 
  3. console.log(person)  // { name'布兰', age: 12 } 

使用扩展操作符给对象添加属性:

  1. let person = { name'布兰' } 
  2. person = {...person, age: 12} 
  3. console.log(person)  // { name'布兰', age: 12 } 

关于使用扩展操作符给对象添加属性,这里有 2 个小技巧:

1.给新对象设置默认值:

  1. // 默认 person 对象的 age 属性值 为 12 
  2. let person = {age: 12, ...{ name'布兰' } } 
  3. console.log(person)  // { age: 12, name'布兰' }  

2.重写对象属性

  1. let person = { name'布兰', age: 12 } 
  2.  
  3. // person 对象的 age 属性被重写为 20 
  4. person = {...person, age: 20 } 
  5. console.log(person)  // { name'布兰', age: 20 } 

8. 设置对象 Getter

设置对象 Getter 通常做法是这样:

  1. let person = { name'布兰' } 
  2. Object.defineProperty(person, 'age', { 
  3.     get() { return 12 }, 
  4.     enumerable: true
  5.     configurable: true 
  6. }) 
  7. console.log(person.age)  // 12 

而有了扩展操作符后可以这么写:

  1. let person = { name'布兰' } 
  2. person = { 
  3.     ...person,  
  4.     get age() { return 12 } 
  5. console.log(person.age)  // 12 

9. 将数组作为函数参数展开

如果我们有一个形参是多个参数的函数,但是当调用的时候发现入参却是一个数组,常规做法是这样:

  1. let arr = [1, 3, 5] 
  2. function fn(a, b, c) { }  
  3. fn.apply(null, arr) 

使用扩展操作符后,就简单多了:

  1. let arr = [1, 3, 5] 
  2. function fn(a, b, c) { }  
  3. fn(...arr) 

10. 无限参数的函数

如果有这么一个累加函数,他会把所有传递进来的参数都加起来,普通做法是把参数都整合到数组里,然后这样做:

  1. function doSum(arr) { 
  2.     return arr.reduce((acc, cur) => acc + cur) 
  3. console.log( doSum([1, 3]) )     // 4 
  4. console.log( doSum([1, 3, 5]) )  // 9 

如果参数不是数组,而是需要一个个传递,相当于函数必须支持无限参数,那可能会这么做:

  1. function doSum() { 
  2.     let sum = 0 
  3.     for(let i = 0, l = arguments.length; i < l; i++){ 
  4.         sum += arguments[i] 
  5.     } 
  6.     return sum 
  7.      
  8.     // 或者 
  9.     // let args = [].slice.call(arguments)  
  10.     // return args.reduce((acc, cur) => acc + cur) 
  11. console.log( doSum(1, 3) )        // 4 
  12. console.log( doSum(1, 3, 5) )     // 9 
  13. console.log( doSum(1, 3, 5, 7) )  // 16 

而有了扩展操作符,就简单多了:

  1. function doSum(...arr) { 
  2.     return arr.reduce((acc, cur) => acc + cur) 
  3. console.log( doSum(1, 3) )        // 4 
  4. console.log( doSum(1, 3, 5) )     // 9 
  5. console.log( doSum(1, 3, 5, 7) )  // 16 

11. 扩展函数的剩余参数

有的时候一个函数需要传递很多的参数,比如小程序页面(WePY)的 onLoad 生命周期函数里就可能有很多别的页面传递过来的参数,然后还需要在函数里进行一些数据初始化工作,这样一来就会显得很臃肿不美观,比如:

  1. function init(a, b, x, y) { 
  2.     // 进行一系列初始化数据工作 

而使用了扩展操作符后,我们就可以按照业务把参数进行解构,把本该在一个函数里进行初始化的工作拆分成多个,可以这么做:

  1. function other( x, y ) {} 
  2. function init(a, b, ...restConfig) { 
  3.     // 使用 a 和 b 参数进行操作 
  4.     // 其余参数传给原始函数 
  5.     return other( ...restConfig ) 

12. 结合 Math 函数使用

比如当需要对一个数组求最大值的时候,通常会这么做:

  1. let arr = [3, 1, 8, 5, 4] 
  2. function max(arr) { 
  3.     return [].concat(arr).sort((a, b) => b - a) 
  4. console.log(max(arr)[0])  // 8 
  5.  
  6. // 或者 
  7. arr.reduce((acc, cur) => Math.max(acc, cur))  // 8 
  8.  
  9. // 又或者 
  10. Math.max.apply(null, arr)  // 8 

但是使用扩展操作符后,能够把给数组求最大值写得更加简洁:

  1. let arr = [3, 1, 8, 5, 4] 
  2. let max = Math.max(...arr) 
  3. console.log(max)  // 8 

13. 在 new 表达式中使用

假设有一个数组格式的日期,想要通过 Date 构造函数创建一个日期实例的话,可能会这么做:

  1. let arr = [2021, 1, 1] 
  2. let date = new Date([].toString.call(arr)) 
  3. console.log(date)  // 'Mon Feb 01 2021 00:00:00 GMT+0800 (中国标准时间)' 
  4.  
  5. // 或者 
  6. let date2 = new (Function.prototype.bind.apply( 
  7.     Date,  
  8.     [null].concat(arr) 
  9. )) 
  10. console.log(date2)  // 'Mon Feb 01 2021 00:00:00 GMT+0800 (中国标准时间)'  

而有了扩展操作符就简单多了:

  1. let arr = [2021, 1, 1] 
  2. let date = new Date(...arr) 
  3. console.log(date)  // 'Mon Feb 01 2021 00:00:00 GMT+0800 (中国标准时间)' 

总结

这个操作符真可谓使用简单无脑,但是功能效率上不得不说很强大,所以我们要做的就是只要记住在什么时候使用它就好了,于是乎为了让大家能更好的记住这 13 种使用场景,我特意做了一个图,方便大家记忆,是不是很贴?。以上这些只列了 13 种写法,我觉得作为一个这么强大的操作符,肯定有更多使用的场景。


 

责任编辑:姜华 来源: 大海我来了
相关推荐

2009-08-29 08:41:07

Windows 7新功能

2011-09-16 09:06:20

Smalltalk

2021-02-02 21:42:30

VS Code编辑器开发

2021-01-18 09:55:46

Spring代码Java

2010-12-08 09:59:10

CSS

2021-12-09 13:30:17

微软

2021-04-13 10:07:08

Python软件包编程语言

2021-04-25 10:15:38

Python编程语言软件包

2021-01-24 11:55:40

spring升华代码的技巧开发

2011-03-31 14:22:28

Chrome插件

2011-05-12 09:12:16

Ubuntu 11.0

2017-05-24 18:00:13

AndroidAndroid DatView

2013-05-06 22:52:10

智能手机交互方式用户体验

2016-05-05 10:54:53

Android开发应用

2021-01-11 08:21:34

spring升华代码的技巧开发

2023-07-04 08:19:25

IDEA插件

2020-11-03 15:10:55

Spring Batc框架Java

2021-07-13 10:59:49

Python可视化

2011-04-19 09:08:09

web工具项目管理

2023-07-18 08:46:34

开发必备软件工具
点赞
收藏

51CTO技术栈公众号