【前端基础系列】slice方法将类数组转换数组实现原理
问题描述
在日常编码中会遇到将类数组对象转换为数组的问题,其中常用到的一种方式使用Array.prototype.slice()方法。
类数组对象
所谓的类数组对象,JavaScript对它们定义为:它们看起来很像数组,只是具有部分和数组相同特性:
- 拥有length属性
- 元素保存在对象中,可以通过索引访问
但是没有数组的其他方法,例如:push、slice、indexOf等。
转换过程
例如:
var foo = {
0: 'Java',
1: 'Python',
2: 'JavaScript',
length: 3
};
// 因为foo对象本身并没有slice方法,所以通过call调用
var arr = Array.prototype.slice.call(foo); // [‘Java’,’Python’,’JavaScript’]
那么问题来了,为什么slice方法可以将对象转换为数组?最简单的方式就是查看源码实现。
源码实现
可以查看V8引擎中的Array内部方法实现
function ArraySlice(start, end) {
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.slice");
var array = TO_OBJECT(this);
var len = TO_LENGTH(array.length);
var start_i = TO_INTEGER(start);
var end_i = len;
if (!IS_UNDEFINED(end)) end_i = TO_INTEGER(end);
if (start_i < 0) {
start_i += len;
if (start_i < 0) start_i = 0;
} else {
if (start_i > len) start_i = len;
}
if (end_i < 0) {
end_i += len;
if (end_i < 0) end_i = 0;
} else {
if (end_i > len) end_i = len;
}
var result = ArraySpeciesCreate(array, MaxSimple(end_i - start_i, 0)); // 先转换为数组
if (end_i < start_i) return result; // 如果没有任何参数,直接返回数组
if (UseSparseVariant(array, len, IS_ARRAY(array), end_i - start_i)) {
%NormalizeElements(array);
if (IS_ARRAY(result)) %NormalizeElements(result);
SparseSlice(array, start_i, end_i - start_i, len, result);
} else {
SimpleSlice(array, start_i, end_i - start_i, len, result);
}
result.length = end_i - start_i;
return result;
}
由以上代码可以看出,当没有输入参数的时候,会创建一个新数组,然后把当前数组的所有元素扔进去,最后返回这个新数组。
参考
【前端基础系列】slice方法将类数组转换数组实现原理的更多相关文章
- JS数组 选定元素slice() slice() 方法可从已有的数组中返回选定的元素。 语法 arrayObject.slice(start,end)
选定元素slice() slice() 方法可从已有的数组中返回选定的元素. 语法 arrayObject.slice(start,end) 参数说明: 1.返回一个新的数组,包含从 start 到 ...
- JS基础篇--sort()方法的用法,参数以及排序原理
JS基础篇--sort()方法的用法,参数以及排序原理 sort() 方法用于对数组的元素进行排序,并返回数组.默认排序顺序是根据字符串Unicode码点.语法:arrayObject.sort( ...
- 快学Scala 第三课 (定长数组,变长数组, 数组循环, 数组转换, 数组常用操作)
定长数组定义: val ar = new Array[Int](10) val arr = Array("aa", "bb") 定长数组赋值: arr(0) = ...
- 【前端基础系列】理解bind方法使用与实现
方法描述 bind()方法创建一个新函数,当被调用时,将其this关键字设置为提供的值. 语法说明 fn.bind(thisArg,arg1,arg2,..) 参数说明 thisArg:当绑定函数被调 ...
- js作用域与执行环境(前端基础系列)
一.作用域(what?) 官方解释是:"一段程序代码中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域." 单从文字理解比较难懂,举个栗子: ...
- javascript 命名空间与运用(前端基础系列)
所谓代码,当你随便命名一个变量:var name = "ukerxi"; 就是一句代码:但当你的代码写出来后,对于后续维护及阅读的人,就可以看出代码是否,易读,易理解:优雅的代码总 ...
- “use strict” 严格模式使用(前端基础系列)
ECMAscript5添加一种严格模式的运行模式("use strict"),让你的js语句在更加严格的环境下进行运行: 一.主要作用: 消除版本javascript中一些不合理及 ...
- openlayers3 基础(常见方法,类及实现)
ol3接口大全1.ol.Map类:(地图容器类) 实现: ol.Map(参数) 参数说明:1.1 target,说明地图所在的html元素. 如果没有指定,必须调用ol.Map类的setTarget( ...
- java基础37 集合框架工具类Collections和数组操作工具类Arrays
一.集合框架工具类:Collections 1.1.Collections类的特点 该工具类中所有的方法都是静态的 1.2.Collections类的常用方法 binarySearch(List< ...
随机推荐
- 036_lua应用扩展
一.request_id定义 ## # request id ## lua_package_path '/opt/nginx/conf/lua/lib/?.lua'; init_by_lua ' uu ...
- Zeppelin0.7.2结合hive解释器进行报表展示
前提:服务器已经安装好了hadoop_client端即hadoop的环境hbase,hive等相关组件 1.环境和变量配置①拷贝hive的配置文件hive-site.xml到zeppelin-0.7. ...
- OpenStack实践系列⑨云硬盘服务Cinder
OpenStack实践系列⑨云硬盘服务Cinder八.cinder8.1存储的三大分类 块存储:硬盘,磁盘阵列DAS,SAN存储 文件存储:nfs,GluserFS,Ceph(PB级分布式文件系统), ...
- Callcenter 模块解析
CallCenter模块详细介绍 一. Callcenter模块说明: 提供了呼叫中心的ACD功能,把客户端通过不同的”方案”和”等级”分配给来电,一个以”评分”为基础的系统是用来分配这些呼入.来电者 ...
- 常用的ORM框架
现在,很多项目使用ORM的框架构架实现数据持久层,下面列举一些常用的ORM框架有,后续分节介绍. Java:Hibernate和Mybatis(前身iBatis) .Net:EF6与EFCore.Da ...
- Mysql41道练习题
1.自行创建测试数据 2.查询“生物”课程比“物理”课程成绩高的所有学生的学号.ps:针对的是自己的生物成绩比物理成绩高,再把符合条件的学生的学号查出来: # 查到 生物 和 物理的 id: sele ...
- ubuntu18.04安装xmind8
1.先去官网下载:https://www.xmind.net/download/xmind8/ 2.默认下载到/home/guojihai/下载/目录下然后把xmind-8-update8-linux ...
- AndroidManifest.xml 最全详解
AndroidManifest.xml 是每个android程序中必须的文件,它位于整个项目的根目录.我们每天都在使用这个文件,往里面配置程序运行所必要的组件,权限,以及一些相关信息.但是对于这个文件 ...
- 洛谷P3247 [HNOI2016]最小公倍数 [分块,并查集]
洛谷 思路 显然,为了达到这个最小公倍数,只能走\(a,b\)不是很大的边. 即,当前询问的是\(A,B\),那么我们只能走\(a\leq A,b\leq B\)的边. 然而,为了达到这最小公倍数,又 ...
- 大数据mapreduce俩表join之python实现
二次排序 在Hadoop中,默认情况下是按照key进行排序,如果要按照value进行排序怎么办?即:对于同一个key,reduce函数接收到的value list是按照value排序的.这种应用需求在 ...