详解ES6 扩展运算符的使用与注意事项


Posted in Javascript onNovember 12, 2020

扩展运算符 spread syntax 又叫展开语法,写法是 ...,顾名思义,其实是用来展开字符串,数组和对象的一种语法,可以在函数调用/数组构造时, 将数组表达式或者 string 在语法层面展开;还可以在构造字面量对象时, 将对象表达式按 key-value 的方式展开。常用的语法如下:

//函数调用:
myFunction(...iterableObj);

//字面量数组构造或字符串:
[...iterableObj, '4', ...'hello', 6];

// 构造字面量对象时,进行克隆或者属性拷贝(ECMAScript 2018规范新增特性):
let objClone = { ...obj };

在函数调用时使用扩展运算符相当于使用 Function.prototype.apply

function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction(...args);

//相当于
function myFunction(x, y, z) {}
var args = [0, 1, 2];
myFunction.apply(null, args);

apply 不同的是,我们不仅可以将全部参数放到一个数组中,还可以只将其中几个参数用扩展运算符展开,并且可以再一次调用中多次使用扩展运算符。

function myFunction(a, b, c, d, e) {
  console.log(a, b, c, d, e); //-1 0 1 2 3
  console.log(arguments); //[Arguments] { '0': -1, '1': 0, '2': 1, '3': 2, '4': 3 }
}
var args = [0, 1];
myFunction(-1, ...args, 2, ...[3]);

使用 new 关键字来调用构造函数时,不能直接使用数组加上 apply 的方式(apply 执行的是调用 [[Call]] , 而不是构造 [[Construct]])。有了展开语法, 将数组展开为构造函数的参数就很简单了:

var dateFields = [1970, 0, 1]; // 1970年1月1日
var d = new Date(...dateFields);

如果想要不使用扩展运算符实现同样的效果,我们必须用一个函数包装构造函数,将这个新的构造函数的 prototype 设为原构造函数的实例,用 Object.create(constructor.prototype)(这里主要是为了新构造函数原型的修改不影响原构造函数的原型,直接用 constructor.prototype 作为新构造函数的原型也可以实现)。

function applyAndNew(constructor, args) {
  function partial() {
    return constructor.apply(this, args);
  }
  if (typeof constructor.prototype === 'object') {
    partial.prototype = Object.create(constructor.prototype);
  }
  return partial;
}

function myConstructor() {
  console.log('arguments.length: ' + arguments.length);
  console.log(arguments);
  this.prop1 = 'val1';
  this.prop2 = 'val2';
}

var myArguments = ['hi', 'how', 'are', 'you', 'mr', null];
var myConstructorWithArguments = applyAndNew(myConstructor, myArguments);

console.log(new myConstructorWithArguments());
// (myConstructor构造函数中):      arguments.length: 6
// (myConstructor构造函数中):      ["hi", "how", "are", "you", "mr", null]
// ("new myConstructorWithArguments"中): {prop1: "val1", prop2: "val2"}

当然用的最多的还是在字面量数组上,没有展开语法的时候,只能组合使用 push, splice, concat 等方法,来将已有数组元素变成新数组的一部分。有了展开语法, 通过字面量方式, 构造新数组会变得更简单、更优雅:

var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes'];
// ["head", "shoulders", "knees", "and", "toes"]

可以用来实现数组浅拷贝:

var arr = [1, 2, 3];
var arr2 = [...arr]; // like arr.slice()
arr2.push(4);

// arr2 此时变成 [1, 2, 3, 4]
// arr 不受影响

连接多个数组:

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
var arr3 = [...arr1, ...arr2];

扩展运算符还可以将已有对象的所有可枚举(enumerable)属性拷贝到新构造的对象中。该方法为浅拷贝,可以拷贝 Symbol 属性,但不包含原型上的属性和方法。如果同时拷贝多个对象,后面的对象会覆盖前面对象的同名属性。

var obj1 = { foo: 'bar', x: 42, [Symbol('a')]: 123 };
var obj2 = { foo: 'baz', x: 100, y: 13 };

var clonedObj = { ...obj1 };
console.log(clonedObj); //{ foo: 'bar', x: 42, [Symbol(a)]: 123 }

var mergedObj = { ...obj1, ...obj2 };
console.log(mergedObj); //{ foo: 'baz', x: 100, y: 13, [Symbol(a)]: 123 }

该方法的性质和 Object.assign 类似,但是 Object.assign() 函数会触发 setters,而展开语法则不会。

注意事项

  1. 在数组或函数参数中使用展开语法时, 扩展运算符只能用于可迭代对象。
  2. 只有函数调用时,扩展运算符才可以放在圆括号中,否则会报错。
  3. 只能用在函数调用,字面量数组(可以在数组中展开字符串),字面量对象中。
  4. 用于数组的解构赋值的时候,扩展运算符只能处于最后一个。
  5. 展开对象可以是任意可迭代对象。

剩余参数

剩余参数语法允许我们将一个不定数量的参数表示为一个数组。如果函数的最后一个命名参数以 ... 为前缀,则它将成为一个由剩余参数组成的真数组,其中从 0(包括)到 theArgs.length(排除)的元素由传递给函数的实际参数提供。

剩余语法(Rest syntax) 看起来和展开语法完全相同,不同点在于, 剩余参数用于解构数组和对象。从某种意义上说,剩余语法与展开语法是相反的:展开语法将数组展开为其中的各个元素,而剩余语法则是将多个元素收集起来并“凝聚”为单个元素。扩展运算符是用在函数调用,而剩余参数是用在函数声明。

剩余参数和 arguments 对象之间的区别主要有三个:

  • 剩余参数只包含那些没有对应形参的实参,而 arguments 对象包含了传给函数的所有实参。
  • arguments 对象不是一个真正的数组,而剩余参数是真正的 Array 实例,也就是说你能够在它上面直接使用所有的数组方法,比如 sortmapforEach pop
  • arguments 对象还有一些附加的属性 (如 callee 属性)。

如果剩余参数(包括在解构赋值中)右侧有逗号,会抛出 SyntaxError,因为剩余元素必须是函数的最后一个参数或者数组的最后一个元素。

以上就是详解ES6 扩展运算符的详细内容,更多关于ES6 扩展运算符的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
javascript中获取下个月一号,是星期几
Jun 01 Javascript
使用jQuery不判断浏览器高度解决iframe自适应高度问题
Dec 16 Javascript
javascript面向对象之共享成员属性与方法及prototype关键字用法
Jan 13 Javascript
JQuery解析XML的方法小结
Apr 02 Javascript
Javascript数组循环遍历之forEach详解
Nov 07 Javascript
Vue.js系列之vue-router(上)(3)
Jan 03 Javascript
鼠标经过出现气泡框的简单实例
Mar 17 Javascript
BootStrap实现文件上传并带有进度条效果
Sep 11 Javascript
Sublime Text新建.vue模板并高亮(图文教程)
Oct 26 Javascript
在SSM框架下用laypage和ajax实现分页和数据交互的方法
Sep 27 Javascript
vue组件暴露和.js文件暴露接口操作
Aug 11 Javascript
vue中选中多个选项并且改变选中的样式的实例代码
Sep 16 Javascript
在vue中使用image-webpack-loader实例
Nov 12 #Javascript
Vue向后台传数组数据,springboot接收vue传的数组数据实例
Nov 12 #Javascript
JavaScript ES 模块的使用
Nov 12 #Javascript
在vue中给后台接口传的值为数组的格式代码
Nov 12 #Javascript
vue 解决provide和inject响应的问题
Nov 12 #Javascript
vue的$http的get请求要加上params操作
Nov 12 #Javascript
vue 获取url参数、get参数返回数组的操作
Nov 12 #Javascript
You might like
2020显卡排行榜天梯图 显卡天梯图2020年3月最新版
2020/04/02 数码科技
我的论坛源代码(九)
2006/10/09 PHP
PHP获取一年中每个星期的开始和结束日期的方法
2015/02/12 PHP
PHP实现仿Google分页效果的分页函数
2015/07/29 PHP
PHP经典面试题之设计模式(经常遇到)
2015/10/15 PHP
PHP观察者模式示例【Laravel框架中有用到】
2018/06/15 PHP
PHP二维索引数组的遍历实例分析【2种方式】
2019/06/24 PHP
点击进行复制的JS代码实例
2013/08/23 Javascript
javascipt:filter过滤介绍及使用
2014/09/10 Javascript
javascript中SetInterval与setTimeout的定时器用法
2015/08/24 Javascript
JavaScript数据结构与算法之集合(Set)
2016/01/29 Javascript
javascript中不易分清的slice,splice和split三个函数
2016/03/29 Javascript
vue 中的keep-alive实例代码
2018/07/20 Javascript
electron中使用bootstrap的示例代码
2018/11/06 Javascript
jQuery实现当拉动滚动条到底部加载数据的方法分析
2019/01/24 jQuery
Vue实现滑动拼图验证码功能
2019/09/15 Javascript
[03:23:49]2016.12.17日完美“圣”典全回顾
2016/12/19 DOTA
Python版微信红包分配算法
2015/05/04 Python
linux平台使用Python制作BT种子并获取BT种子信息的方法
2017/01/20 Python
新手入门Python编程的8个实用建议
2019/07/12 Python
Django rest framework jwt的使用方法详解
2019/08/08 Python
pytorch:torch.mm()和torch.matmul()的使用
2019/12/27 Python
Django密码存储策略分析
2020/01/09 Python
PyCharm中Matplotlib绘图不能显示UI效果的问题解决
2020/03/12 Python
OpenCV 之按位运算举例解析
2020/06/19 Python
你需要学会的8个Python列表技巧
2020/06/24 Python
Matlab使用Plot函数实现数据动态显示方法总结
2021/02/25 Python
HTML5拖放API实现拖放排序的实例代码
2017/05/11 HTML / CSS
澳大利亚拥有最佳跳伞降落点和最好服务的跳伞项目运营商:Skydive Australia
2018/03/05 全球购物
致100米运动员广播稿
2014/02/14 职场文书
班级旅游计划书
2014/05/03 职场文书
门店业绩提升方案
2014/06/08 职场文书
信用卡工作证明模板
2014/09/14 职场文书
停电通知范文
2015/04/16 职场文书
招商银行收入证明
2015/06/17 职场文书
gtx1650怎么样 gtx1650显卡相当于什么级别
2022/04/08 数码科技