深入理解扩展运算符实现原理
点击上方 前端Q,关注公众号
回复加群,加入前端Q技术交流群
... 作用
扩展运算符(spread)是三个点(...),用于取出参数对象中的所有可遍历属性,浅拷贝到当前对象之中。
常见用法
浅拷贝数组
const a1 = ['test1', 'test2'];
const a2 = [...a1];a2[0] = 'test2';
a2 // ['test2', 'test2']
合并数据
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' ]
解构赋值
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 // []
字符串/类数组转为真正的数组
因为任何定义了遍历器(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']
显然,上面的例子,我们没有考虑到属性的可遍历性判断,那么需要进一步优化。
严谨实现
其实这里分几种情况来考虑就好:
判断是否为数组,数组一定可迭代,则直接复制数组后返回结果即可。
判断是否为实现了遍历器(Iterator)接口的对象,若实现了则转为数组。
如果没有实现遍历器(Iterator)接口的对象,则判断是否为普通字符串/Map/Set等。
均不满足以上条件的话,则抛错。
所以,最后实现为:
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端、小程序等,目前主要专注于高级前端进阶方向的学习。
我偏爱理财,喜欢折腾技术;靠自己的努力已经在广州房车齐全,正在努力奋斗人生中的第一个千万。上方关注后可以加我私信,点击蓝字查看我的奋斗之路。
深入理解扩展运算符实现原理相关推荐
- C语言 位运算符详解 (使用二进制实例深入学习理解位运算符使用原理)
C语言中位运算符共有六种 目录 1.&(按位与) 2. |(按位或) 3.^(按位抑或) 4.~(按位取反)
- ES6-ES11-第一部分-let、const、解构赋值、模板字符串、简化对象写法、箭头函数、函数参数默认值、rest 参数、扩展运算符、Symbol、迭代器、生成器、Promise、Set、Map
根据视频进行整理 [https://www.bilibili.com/video/BV1uK411H7on?p=1] 视频资源(百度网盘): 链接:[https://pan.baidu.com/s/1 ...
- ES6 | let 关键字 + const关键字 + 箭头函数 + rest参数 + 扩展运算符 ... + Symbol + 迭代器 + 生成器 + 变量的解构赋值 + 模板字符串
目录 ECMASript 相关介绍 ECMASript 6 新特性 let 关键字 const关键字 变量的解构赋值 模板字符串 简化对象写法 箭头函数 => 参数默认值 rest参数 扩展运算 ...
- javascript ES6 新特性之 扩展运算符 三个点 ...
对于 ES6 新特性中的 ... 可以简单的理解为下面一句话就可以了: 对象中的扩展运算符(...)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中. 作用类似于 Object.assign() ...
- 了解ES6 The Dope Way第三部分:模板文字,扩展运算符和生成器!
by Mariya Diminsky 通过玛丽亚·迪明斯基(Mariya Diminsky) 了解ES6 The Dope Way第三部分:模板文字,扩展运算符和生成器! (Learn ES6 The ...
- 京东面试官:你是怎么理解 MySQL 的优化原理的?
说起MySQL的查询优化,相信大家收藏了一堆奇技淫巧:不能使用 SELECT*.不使用NULL字段.合理创建索引.为字段选择合适的数据类型..... 你是否真的理解这些优化技巧?是否理解其背后的工作原 ...
- 【分布式ID】理解Snowflake算法的实现原理
1.概述 转载:冷饭新炒:理解Snowflake算法的实现原理 我上次也看了一个视频讲解:[分布式ID]键高并发 分布式 全局唯一 ID 雪花算法 snowflake 2.前提# Snowflake( ...
- ES6高级:扩展运算符,箭头函数,class类,iterator迭代器
2. 扩展运算符 ... 2.1 reset参数 reset参数==必须放在最后==,为了替代arguments,在函数形参中使用,==接受剩余参数==,以==数组==的形式去接受 //1. rese ...
- ES6之三个点(扩展运算符及rest运算符)
ES6中出现了三个点的写法,初次看到一脸懵逼,现在让我们好好来搞清楚这三个点... 首先需要了解的是在ES6中新增了扩展运算符和rest参数,而这两个都是用...三个点来表示的(麻蛋就不能用不同的表示 ...
最新文章
- 目前研制量子计算机,18个量子比特纠缠究竟是什么水平? 量子计算机离我们还有多远?...
- Java重写equals()和hashCode()
- 开发日记-20190409 关键词 理想activity模型
- 【前端面试】数据类型与类型检测
- C# webservice调用方法总结
- 全国计算机民办二本学校排行,艺术类二本院校排名,2018最新民办和公办院校全国排名...
- springMVC配置
- oracle 11g for windows卸载
- 一次linux root密码错修改历程
- 激光雷达+imu_大疆览沃浩界(Livox Horizon)激光雷达测评
- VB.net 调用FFmpeg简单处理视频(类库——6)
- matlab数组元素的个数,matlab数组元素个数
- wifi共享精灵2014最新版 v04.25.001 官方正式版
- APP推广什么是cpa,cps,cpm
- 大白菜U盘重装win7系统教程,PE重装win7系统教程
- 如何快速查找BUG?
- 计算机考试遇到不会读的字,不会读的字怎么打 轻松几招教你怎样打不会读的字...
- karabiner json语法
- 链表(线性表的一种存储结构)
- 商务与经济统计阅读笔记3