点击上方 前端Q,关注公众号

回复加群,加入前端Q技术交流群

... 作用

扩展运算符(spread)是三个点(...),用于取出参数对象中的所有可遍历属性,浅拷贝到当前对象之中。

常见用法

  1. 浅拷贝数组

const a1 = ['test1', 'test2'];
const a2 = [...a1];a2[0] = 'test2';
a2 // ['test2', 'test2']
  1. 合并数据

const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];// ES5 的合并数组
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]// ES6 的合并数组
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]
  1. 解构赋值

const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest  // [2, 3, 4, 5]const [first, ...rest] = [];
first // undefined
rest  // []const [first, ...rest] = ["foo"];
first  // "foo"
rest   // []
  1. 字符串/类数组转为真正的数组

因为任何定义了遍历器(Iterator)接口的对象,都可以用扩展运算符转为真正的数组。

[...'test']
// [ "t", "e", "s", "t"][...document.querySelectorAll('div')]
// [<div>, <div>, <div>]

基本实现原理

如果不用 ...,如何实现一样的功能?由上面的用法,可以知道。扩展运算符主要就是浅拷贝可遍历对象属性,那么我们可以用es5的写法实现如下:

// 简单版实现
function _spread() {for (var ar = [], i = 0; i < arguments.length; i++){ar = ar.concat(arguments[i]);}return ar;
};

用上面的例子测试一下,结果如下:

const a1 = ['test1', 'test2'];
const a2 = _spread(a1);a2[0] = 'test2';
a2 // ['test2', 'test2']

显然,上面的例子,我们没有考虑到属性的可遍历性判断,那么需要进一步优化。

严谨实现

其实这里分几种情况来考虑就好:

  1. 判断是否为数组,数组一定可迭代,则直接复制数组后返回结果即可。

  2. 判断是否为实现了遍历器(Iterator)接口的对象,若实现了则转为数组。

  3. 如果没有实现遍历器(Iterator)接口的对象,则判断是否为普通字符串/Map/Set等。

  4. 均不满足以上条件的话,则抛错。

所以,最后实现为:

function _toConsumableArray(arr) {return (_arrayWithoutHoles(arr) || //  判断是否为数组_iterableToArray(arr) || //  判断是否为实现了遍历器(Iterator)接口的对象_unsupportedIterableToArray(arr) || // 判断是否为普调字符串/Map/Set等_nonIterableSpread() // 则抛错);
}function _nonIterableSpread() {throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}function _unsupportedIterableToArray(o, minLen) {if (!o) return;if (typeof o === "string") return _arrayLikeToArray(o, minLen);var n = Object.prototype.toString.call(o).slice(8, -1);if (n === "Object" && o.constructor) n = o.constructor.name;if (n === "Map" || n === "Set") return Array.from(o);if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _arrayLikeToArray(o, minLen);
}function _iterableToArray(iter) {if ((typeof Symbol !== "undefined" && iter[Symbol.iterator] != null) ||iter["@@iterator"] != null)return Array.from(iter);
}function _arrayWithoutHoles(arr) {if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}function _arrayLikeToArray(arr, len) {if (len == null || len > arr.length) len = arr.length;for (var i = 0, arr2 = new Array(len); i < len; i++) {arr2[i] = arr[i];}return arr2;
}

更多原理探究

我们平时在想一些 es6 的实现的时候,如果想知道其实现原理,那么可以考虑它的 es5 实现,而如果想知道它的严谨实现的话。可以直接去看 babel 编译后的 es5 代码长什么样即可。babel 在线编译网址:https://www.babeljs.cn/repl

如图:

最后

你好,我是winty,末流本科软件工程专业出身,目前就职于腾讯微信,掘金LV5作者。

技术上主导过服务端框架设计,是可视化搭建平台的核心开发,主导过基础库平台搭建/前端性能sdk开发等,接触过包括但不限于服务端、移动端、PC端、小程序等,目前主要专注于高级前端进阶方向的学习。

我偏爱理财,喜欢折腾技术;靠自己的努力已经在广州房车齐全,正在努力奋斗人生中的第一个千万。上方关注后可以加我私信,点击蓝字查看我的奋斗之路。

深入理解扩展运算符实现原理相关推荐

  1. C语言 位运算符详解 (使用二进制实例深入学习理解位运算符使用原理)

    C语言中位运算符共有六种 目录 1.&(按位与) 2. |(按位或) 3.^(按位抑或) 4.~(按位取反)

  2. ES6-ES11-第一部分-let、const、解构赋值、模板字符串、简化对象写法、箭头函数、函数参数默认值、rest 参数、扩展运算符、Symbol、迭代器、生成器、Promise、Set、Map

    根据视频进行整理 [https://www.bilibili.com/video/BV1uK411H7on?p=1] 视频资源(百度网盘): 链接:[https://pan.baidu.com/s/1 ...

  3. ES6 | let 关键字 + const关键字 + 箭头函数 + rest参数 + 扩展运算符 ... + Symbol + 迭代器 + 生成器 + 变量的解构赋值 + 模板字符串

    目录 ECMASript 相关介绍 ECMASript 6 新特性 let 关键字 const关键字 变量的解构赋值 模板字符串 简化对象写法 箭头函数 => 参数默认值 rest参数 扩展运算 ...

  4. javascript ES6 新特性之 扩展运算符 三个点 ...

    对于 ES6 新特性中的 ... 可以简单的理解为下面一句话就可以了: 对象中的扩展运算符(...)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中. 作用类似于 Object.assign() ...

  5. 了解ES6 The Dope Way第三部分:模板文字,扩展运算符和生成器!

    by Mariya Diminsky 通过玛丽亚·迪明斯基(Mariya Diminsky) 了解ES6 The Dope Way第三部分:模板文字,扩展运算符和生成器! (Learn ES6 The ...

  6. 京东面试官:你是怎么理解 MySQL 的优化原理的?

    说起MySQL的查询优化,相信大家收藏了一堆奇技淫巧:不能使用 SELECT*.不使用NULL字段.合理创建索引.为字段选择合适的数据类型..... 你是否真的理解这些优化技巧?是否理解其背后的工作原 ...

  7. 【分布式ID】理解Snowflake算法的实现原理

    1.概述 转载:冷饭新炒:理解Snowflake算法的实现原理 我上次也看了一个视频讲解:[分布式ID]键高并发 分布式 全局唯一 ID 雪花算法 snowflake 2.前提# Snowflake( ...

  8. ES6高级:扩展运算符,箭头函数,class类,iterator迭代器

    2. 扩展运算符 ... 2.1 reset参数 reset参数==必须放在最后==,为了替代arguments,在函数形参中使用,==接受剩余参数==,以==数组==的形式去接受 //1. rese ...

  9. ES6之三个点(扩展运算符及rest运算符)

    ES6中出现了三个点的写法,初次看到一脸懵逼,现在让我们好好来搞清楚这三个点... 首先需要了解的是在ES6中新增了扩展运算符和rest参数,而这两个都是用...三个点来表示的(麻蛋就不能用不同的表示 ...

最新文章

  1. 目前研制量子计算机,18个量子比特纠缠究竟是什么水平? 量子计算机离我们还有多远?...
  2. Java重写equals()和hashCode()
  3. 开发日记-20190409 关键词 理想activity模型
  4. 【前端面试】数据类型与类型检测
  5. C# webservice调用方法总结
  6. 全国计算机民办二本学校排行,艺术类二本院校排名,2018最新民办和公办院校全国排名...
  7. springMVC配置
  8. oracle 11g for windows卸载
  9. 一次linux root密码错修改历程
  10. 激光雷达+imu_大疆览沃浩界(Livox Horizon)激光雷达测评
  11. VB.net 调用FFmpeg简单处理视频(类库——6)
  12. matlab数组元素的个数,matlab数组元素个数
  13. wifi共享精灵2014最新版 v04.25.001 官方正式版
  14. APP推广什么是cpa,cps,cpm
  15. 大白菜U盘重装win7系统教程,PE重装win7系统教程
  16. 如何快速查找BUG?
  17. 计算机考试遇到不会读的字,不会读的字怎么打 轻松几招教你怎样打不会读的字...
  18. karabiner json语法
  19. 链表(线性表的一种存储结构)
  20. 商务与经济统计阅读笔记3

热门文章

  1. 南开大学张昊计算机,纽约南开校友会隆重举办纪念南开大学建校100周年庆典
  2. 洛谷B2006 地球人口承载力估计
  3. 计算机二级Python第二弹课后题来袭!冲冲冲!!!
  4. Django项目使用QQ实现第三方登录
  5. 合伙企业对外债务如何承担
  6. 腾讯云服务器备案全流程 40天备案的血与泪
  7. python全局变量(模块法和global)
  8. C# Windows系统音量调节Demo源码
  9. boost::geometry::ever_circling_iterator用法的测试程序
  10. GoDaddy域名过户PUSH攻略