js 三个点 “…” 省略号的语法

概念

“…”是ES6的新语法,该写法在js的不同语境中有不同的解释,可解释为展开语法(Spread syntax)和剩余语法(Rest syntax) ,写法相同,但作用却是完全相反的,使用时要注意区分

(本文主要参考MDN官网说明编写)

展开语法(Spread syntax)

该语法可简单的理解为浅拷贝,即将对象的一层可枚举属性拷贝出来;
官方解释:可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造字面量对象时, 将对象表达式按key-value的方式展开。( 字面量一般指 [1, 2, 3] 或者 {name: “mdn”} 这种简洁的构造方式)

简单示例:
function sum(x, y, z) {return x + y + z;
}const numbers = [1, 2, 3];console.log(sum(...numbers));
// output: 6console.log(sum.apply(null, numbers));
// output: 6
场景语法
  • 函数调用:
myFunction(...iterableObj);
  • 字面量数组构造或字符串:
[...iterableObj, '4', ...'hello', 6];
  • 构造字面量对象时,进行克隆或者属性拷贝(ECMAScript 2018规范新增特性):
let objClone = { ...obj };
进阶示例
  1. 在函数调用时使用展开语法等价于apply的方式
    如果想将数组元素迭代为函数参数,一般使用Function.prototype.apply 的方式进行调用。
function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction.apply(null, args);

有了展开语法,可以这样写(所有参数都可以通过展开语法来传值,也不限制多次使用展开语法):

function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction(...args);function myFunction(v, w, x, y, z) { }
var args = [0, 1];
myFunction(-1, ...args, 2, ...[3]);
  1. 使用 new 关键字来调用构造函数时,不能直接使用数组+ apply 的方式(apply 执行的是调用 [[Call]] , 而不是构造 [[Construct]])。当然, 有了展开语法, 将数组展开为构造函数的参数就很简单了:
var dateFields = [1970, 0, 1]; // 1970年1月1日
var d = new Date(...dateFields);
  1. 没有展开语法的时候,只能组合使用 push, splice, concat 等方法,来将已有数组元素变成新数组的一部分。有了展开语法, 通过字面量方式, 构造新数组会变得更简单、更优雅(和参数列表的展开类似, … 在构造字面量数组时, 可以在任意位置多次使用.):
var parts = ['shoulders', 'knees'];
var lyrics = ['head', ...parts, 'and', 'toes'];
// ["head", "shoulders", "knees", "and", "toes"]
  1. 数组拷贝(copy)

注:实际上, 展开语法和 Object.assign() 行为一致, 执行的都是浅拷贝(只遍历一层)。如果想对多维数组进行深拷贝, 下面的示例就有些问题了。

var arr = [1, 2, 3];
var arr2 = [...arr]; // like arr.slice()
arr2.push(4);// arr2 此时变成 [1, 2, 3, 4]
// arr 不受影响var a = [[1], [2], [3]];
var b = [...a];
b.shift().shift(); // 1
// 此时a数组也会受到影响: [[2], [3]]
  1. 连接多个数组

Array.concat 函数常用于将一个数组连接到另一个数组的后面。如果不使用展开语法, 代码可能是下面这样的:

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
// 将 arr2 中所有元素附加到 arr1 后面并返回
var arr3 = arr1.concat(arr2);

使用展开语法:

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

Array.unshift 方法常用于在数组的开头插入新元素/数组. 不使用展开语法, 示例如下:

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
// 将 arr2 中的元素插入到 arr1 的开头
Array.prototype.unshift.apply(arr1, arr2) // arr1 现在是 [3, 4, 5, 0, 1, 2]

如果使用展开语法, 代码如下: [请注意, 这里使用展开语法创建了一个新的 arr1 数组, Array.unshift 方法则是修改了原本存在的 arr1 数组]:

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1 = [...arr2, ...arr1]; // arr1 现在为 [3, 4, 5, 0, 1, 2]
  1. 构造字面量对象时使用展开语法

其行为是, 将已有对象的所有可枚举(enumerable)属性拷贝到新构造的对象中.

浅拷贝(Shallow-cloning, 不包含 prototype) 和对象合并, 可以使用更简短的展开语法。而不必再使用 Object.assign() 方式.

var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };var clonedObj = { ...obj1 };
// 克隆后的对象: { foo: "bar", x: 42 }var mergedObj = { ...obj1, ...obj2 };
// 合并后的对象: { foo: "baz", x: 42, y: 13 }

注:Object.assign() 函数会触发 setters,而展开语法则不会。

6.1 不能替换或者模拟 Object.assign() 函数:
var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };
const merge = ( ...objects ) => ( { ...objects } );var mergedObj = merge ( obj1, obj2);
// Object { 0: { foo: 'bar', x: 42 }, 1: { foo: 'baz', y: 13 } }var mergedObj = merge ( {}, obj1, obj2);
// Object { 0: {}, 1: { foo: 'bar', x: 42 }, 2: { foo: 'baz', y: 13 } }

在这段代码中, 展开操作符(spread operator)并没有按预期的方式执行: 而是先将多个解构变为剩余参数(rest parameter), 然后再将剩余参数展开为字面量对象。

注:在函数调用时使用展开语法,请注意不能超过 JavaScript 引擎限制的最大参数个数(65536)。

浏览器版本支持
  1. Spread in array literals
  2. Spread in object literals
  3. Spread in function calls

剩余参数

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

简单示例:
function sum(...theArgs) {return theArgs.reduce((previous, current) => {return previous + current;});
}console.log(sum(1, 2, 3));
// output: 6console.log(sum(1, 2, 3, 4));
// output: 10
场景语法
function(a, b, ...theArgs) {// ...
}

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

在上面的例子中,theArgs将收集该函数的第三个参数(因为第一个参数被映射到a,而第二个参数映射到b)和所有后续参数。

剩余参数和 arguments对象的区别

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

  • 剩余参数只包含那些没有对应形参的实参,而 arguments 对象包含了传给函数的所有实参。
  • arguments对象不是一个真正的数组,而剩余参数是真正的 Array实例,也就是说你能够在它上面直接使用所有的数组方法,比如 sort,map,forEach或pop。
  • arguments对象还有一些附加的属性 (如callee属性)。
进阶示例
  1. 因为theArgs是个数组,所以你可以使用length属性得到剩余参数的个数:
function fun1(...theArgs) {alert(theArgs.length);
}fun1();  // 弹出 "0", 因为theArgs没有元素
fun1(5); // 弹出 "1", 因为theArgs只有一个元素
fun1(5, 6, 7); // 弹出 "3", 因为theArgs有三个元素
  1. 下例中,剩余参数包含了从第二个到最后的所有实参,然后用第一个实参依次乘以它们:
function multiply(multiplier, ...theArgs) {return theArgs.map(function (element) {return multiplier * element;});
}var arr = multiply(2, 1, 2, 3);
console.log(arr);  // [2, 4, 6]
  1. 下例演示了你可以在剩余参数上使用任意的数组方法,而arguments对象不可以:
function sortRestArgs(...theArgs) {var sortedArgs = theArgs.sort();return sortedArgs;
}alert(sortRestArgs(5,3,7,1)); // 弹出 1,3,5,7function sortArguments() {var sortedArgs = arguments.sort();return sortedArgs; // 不会执行到这里
}alert(sortArguments(5,3,7,1)); // 抛出TypeError异常:arguments.sort is not a function
  1. 为了在arguments对象上使用Array方法,它必须首先被转换为一个真正的数组。
function sortArguments() {var args = Array.prototype.slice.call(arguments);var sortedArgs = args.sort();return sortedArgs;
}
console.log(sortArguments(5, 3, 7, 1)); // shows 1, 3, 5, 7
浏览器版本支持
  1. Rest parameters
  2. Destructuring rest parameters

js 三个点 “...“ 省略号的语法相关推荐

  1. day01 js三种导入html的方法、js书写规范、变量的基本使用、变量提升

    昨天是初学js的第一天,为什么今天才写,我觉得这样可以帮助我复习昨天的知识,加深对js的理解. 我之前学过java的,昨天转入js的学习,对js略有些体会和大家分享下,js刚入门感觉js相对于java ...

  2. Js基础引导(二)——语法

    朋友,你好. 欢迎进入JS基础引导--语法篇,本篇内容是JS的基本概念(常识) 语法: JS语法大量借鉴了其他C语言或者类C语言(如java),因此,熟悉这些语言对于学习JS会很轻松,同样的,会了JS ...

  3. eclipse加速之禁用JS、jsp等文件的语法验证

    eclipse加速之禁用JS.jsp等文件的语法验证 去除eclipse的JS验证: 将windows->preference->Java Script->Validator-> ...

  4. 十分钟,学会使用js三种方法创建本地json数据文件

    前言 在干业务时,需要得到一份全国省市到街道的区划数据,刚好业务中连接了高德地图,高德地图又提供了区划的api,这下只需要把数据写到json里了.什么!你说你还不会用js创建json文件?没关系,只需 ...

  5. 网络协议的三要素:语义、语法、时序

    网络协议的三要素:语义.语法.时序 语义 需要发出何种控制信息,完成何种动作以及做出何种响应 语法 数据与控制信息的结构或格式 时序 事件实现顺序的详细说明

  6. Js(三)将es6语法转换成es5语法

    前言 本章主要讲述将es6语法的js,转换成es5语法 运用场景:由于Jmeter上面只适配es5语法的js,而某朋友公司前端都是写的es6语法的js,为了能在Jmeter上能够兼容,故进行相关转换 ...

  7. vue.js 三种方式安装--npm安装

    Vue.js是一个构建数据驱动的 web 界面的渐进式框架.     Vue.js 的目标是通过简单的 API 实现响应的数据绑定和组合的视图组件.它不仅易上手,便于与第三方库或既有项目整合.     ...

  8. vue.js三种安装方式

    Vue.js(读音 /vjuː/, 类似于 view)是一个构建数据驱动的 web 界面的渐进式框架.Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件.它不仅易于上手 ...

  9. Go 三个点省略号...使用总结

    Go语言中省略号"..."有3种用法,下面会一一介绍. Tips:以下测试程序中所涉及地址在不同机器打印也不同. 目录 使用在数组中 打散Slice 变长的函数参数 使用在数组中 ...

最新文章

  1. Aspose.Words导出图片 表格 Interop.Word
  2. blob html 预览_Blob | HTML 5 API | JavaScript 权威指南
  3. SAP RETAIL物料组的分配规则
  4. CSP认证201803-2 碰撞的小球[C++题解]:模拟
  5. python 空值_数据库中的空值与NULL的区别以及python中的NaN和None
  6. rnn 梯度消失爆炸
  7. window 10下 Spark 安装简单使用
  8. SpringMVC的请求-获得请求参数-静态资源访问的开启
  9. Linux终端打开一只小马,Linux 终端上的漂亮小马
  10. android 删除开机动画,Android删除开机动画bootanimation.zip
  11. 学会这招,轻松实现批量PDF转jpg,快来码住
  12. 获取 CSDN 1024 程序员节勋章教程
  13. 软件架构-事件驱动架构
  14. 深圳名校最新出炉 学校学区房房价飙升-查查吧深圳学区房地图
  15. Maven启动被终止---构建路径指定执行环境 J2SE-1.5。工作空间中没有与此环境严格兼容的JRE...
  16. 编程题目 定义栈的数据类型,请在类型中实现一个能够得到栈最小元素的minx函数。...
  17. Mac免费屏保 Brooklyn 苹果logo
  18. Linux目录结构,命令,文件类型学习
  19. 如何写一个一天爬取 100 万张网页的爬虫
  20. show和shown区别

热门文章

  1. STM32串口首字节丢失问题
  2. 轻松学会spire.xls的常规操作
  3. 攻防世界-MISC:ext3
  4. loading页面加载(等待页面加载完毕再隐藏loading页面)
  5. 安装MCD火星大气数据库
  6. Android 基础知识4-3.3 Button(按钮)与ImageButton(图像按钮)详解
  7. k8s-kubeadm和Harbor私有仓库部署
  8. 考研复试班学姐揭秘考研复试中导师最爱问的问题
  9. 1.5 08:多边形内角和
  10. 人工智能简历-计算机视觉简历