浅谈javascript的Array.prototype.slice.call


Posted in Javascript onAugust 31, 2015

写字前面

在js中我们经常会看到Array.prototype.slice.call(arguments,0)的写法,当然,这个方法的作用也许大家都明白,那就是把类数组对象转换成一个真正的数组。关于这个方法,我说说自己的理解。

这里涉及到slice()方法和call()方法,所以先简单说说这两个方法。

slice()方法

数组和字符串都有这个slice方法,这个方法的作用是截取一段数据。它接收两个参数,第一个参数是要截取的位置索引,第二参数可选,表示要截取到的结束位置,但是不包括结束位置。在数组中,该方法的返回值是包含截取元素的组成的数组,在字符串中,该方法的返回值是包含截取字符串组成的字符串。

该方法也可以传入负数值,当参数为负数的时候,将参数和数组或字符串的长度相加得到的正数作为实际的参数。

如下:

[1,2,3,4,5,6].slice(2,4);

[1,2,3,4,5,6].slice(-4,-2);

返回值均为[3,4],为数组。

'everything'.slice(2,4);

'everything'.slice(-4,-2);

返回值分别为'er'和'hi',为字符串。

如果之传入一个参数的话,那就是输出从开始位置到结束位置的所有元素。不再举例。

字符串的其他类似方法

在字符串中,和slice()方法类型的还有两个方法:

substring()和substr()方法。

其中,substring()方法表示返回从开始位置到结束位置的字符串,substr()接收两个参数,第一个参数表示开始位置,第二个参数表示要截取的字符个数,和前两个方法略有不同。

当传入方法的参数为负数时,这三种方法又略有不同。

当传入方法的参数为负数时:

slice()像上面说的,是负数加上字符串的长度得出相应的正值;

substring()方法的参数均置为零;

substr()方法的第一个参数为负值加上字符串长度得到的正值,第二个参数置为零。

call()和apply()方法

call()和apply()方法主要是用来扩充函数的作用域。

call()和apply()方法接收两个参数:

apply():第一个参数是作用域,第二个是参数数组,其中第二个参数可以是数组实例,也可以是arguments对象。

call()方法也接收两个参数,仅仅在于和apply()的传参方式不同:传递函数的参数必须逐个写入。

鉴于这里不是重点,在这里就不再赘述。

Array.prototype.slice.call(arguments,0)

在Array.prototype.slice.call(arguments,0)中,Array.prototype.slice调用的是Array的原型方法,对于正真的数组是有slice()方法,但是对于像arguments或者自己定义的一些类数组对象虽然存在length等若干属性,但是并没有slice()方法,所以对于这种类数组对象就得使用原型方法来使用slice()方法,即Array.prototype.slice(如果在自定义中的类数组对象中自定义了slice()方法,那么自然可以直接调用)。

所以,Array.prototype.slice.call(arguments,0)的意思就可以这样理解:对于arguments类数组,我们调用Array.prototype.slice原型方法,并用call()方法,将作用域限定在arguments中,这里Array.prototype就可以理解为arguments,同参数0为slice()方法的第一个参数,即开始位置索引。通过这种方法就将arguments类数组转换成了真数组。

当然,把arguments转换为数组也可以用遍历,那样代码自然就会多一些,而且不够直接。

我们知道,Array.prototype.slice.call(arguments)能将具有length属性的对象转成数组,除了IE下的节点集合(因为ie下的dom对象是以com对象的形式实现的,js对象与com对象不能进行转换)
如:

var a={length:2,0:'first',1:'second'};
 Array.prototype.slice.call(a);// ["first", "second"]
 var a={length:2};
 Array.prototype.slice.call(a);// [undefined, undefined]

可能刚开始学习js的童鞋并不是很能理解这句为什么能实现这样的功能。比如我就是一个,所以,来探究一下。

首先,slice有两个用法,一个是String.slice,一个是Array.slice,第一个返回的是字符串,第二个返回的是数组,这里我们看第2个。

Array.prototype.slice.call(arguments)能够将arguments转成数组,那么就是arguments.toArray().slice();到这里,是不是就可以说Array.prototype.slice.call(arguments)的过程就是先将传入进来的第一个参数转为数组,再调用slice?
 
再看call的用法,如下例子

var a = function(){
   console.log(this);  // 'littledu'
   console.log(typeof this);   // Object
   console.log(this instanceof String);  // true
 }
 a.call('littledu');

可以看出,call了后,就把当前函数推入所传参数的作用域中去了,不知道这样说对不对,但反正this就指向了所传进去的对象就肯定的了。
到这里,基本就差不多了,我们可以大胆猜一下slice的内部实现,如下

Array.prototype.slice = function(start,end){
   var result = new Array();
   start = start || 0;
   end = end || this.length; //this指向调用的对象,当用了call后,能够改变this的指向,也就是指向传进来的对象,这是关键
   for(var i = start; i < end; i++){
      result.push(this[i]);
   }
   return result;
 }

大概就是这样吧,理解就行,不深究。

最后,附个转成数组的通用函数

var toArray = function(s){
  try{
    return Array.prototype.slice.call(s);
  } catch(e){
      var arr = [];
      for(var i = 0,len = s.length; i < len; i++){
        //arr.push(s[i]);
        arr[i] = s[i]; //据说这样比push快
      }
       return arr;
  }
}
Javascript 相关文章推荐
利用javascript/jquery对上传文件格式过滤的方法
Jul 25 Javascript
JavaScript写的一个自定义弹出式对话框代码
Jan 17 Javascript
获取dom元素那些讨厌的位置封装代码
Jun 23 Javascript
js计算德州扑克牌面值的方法
Mar 04 Javascript
jQuery插件jRumble实现网页元素抖动
Jun 05 Javascript
javascript获取网页宽高方法汇总
Jul 19 Javascript
jQuery Easyui Tabs扩展根据自定义属性打开页签
Aug 15 Javascript
JS插件plupload.js实现多图上传并显示进度条
Nov 29 Javascript
js数字滑动时钟的简单实现(示例讲解)
Aug 14 Javascript
微信小程序实现蒙版弹出窗功能
Sep 17 Javascript
JS实现字体背景跑马灯
Jan 06 Javascript
JS数组去重详情
Nov 07 Javascript
jquery.mousewheel实现整屏翻屏效果
Aug 30 #Javascript
浅谈JavaScript超时调用和间歇调用
Aug 30 #Javascript
javascript中substring()、substr()、slice()的区别
Aug 30 #Javascript
IE8下jQuery改变png图片透明度时出现的黑边
Aug 30 #Javascript
javascript中sort() 方法使用详解
Aug 30 #Javascript
javascript中的正则表达式使用详解
Aug 30 #Javascript
jQuery鼠标事件汇总
Aug 30 #Javascript
You might like
overlord人气高涨,却被菲利普频繁举报,第四季很难在国内上映
2020/05/06 日漫
windows环境下php配置memcache的具体操作步骤
2013/06/09 PHP
解析smarty模板中类似for的功能实现
2013/06/18 PHP
PHP实现删除非站内外部链接实例代码
2014/06/17 PHP
PHP实现按之字形顺序打印二叉树的方法
2018/01/16 PHP
PHP开启目录引索+fancyindex漂亮目录浏览带搜索功能
2019/09/23 PHP
关于JavaScript的面向对象和继承有利新手学习
2013/01/11 Javascript
完美解决AJAX跨域问题
2013/11/01 Javascript
开发插件的两个方法jquery.fn.extend与jquery.extend
2013/11/21 Javascript
jquery ajax跨域解决方法(json方式)
2014/02/04 Javascript
js中跨域方法原理详解
2015/07/19 Javascript
JS实现合并两个数组并去除重复项只留一个的方法
2015/12/17 Javascript
jquery实现限制textarea输入字数的方法
2017/09/06 jQuery
angularjs实现柱状图动态加载的示例
2017/12/11 Javascript
vue内置指令详解
2018/04/03 Javascript
如何获取TypeScript的声明文件.d.ts
2018/05/01 Javascript
vue 双向数据绑定的实现学习之监听器的实现方法
2018/11/30 Javascript
Angular6新特性之Angular Material
2018/12/28 Javascript
[01:45]亚洲邀请赛互动指南虚拟物品介绍
2015/01/30 DOTA
Python程序中用csv模块来操作csv文件的基本使用教程
2016/03/03 Python
Python向excel中写入数据的方法
2019/05/05 Python
Django urls.py重构及参数传递详解
2019/07/23 Python
pip安装python库的方法总结
2019/08/02 Python
python多线程同步实例教程
2019/08/11 Python
pymysql模块的使用(增删改查)详解
2019/09/09 Python
python实现将range()函数生成的数字存储在一个列表中
2020/04/02 Python
15款Python编辑器的优缺点,别再问我“选什么编辑器”啦
2020/10/19 Python
HTML5之SVG 2D入门10—滤镜的定义及使用
2013/01/30 HTML / CSS
AVON雅芳官网:世界上最大的美容化妆品公司之一
2016/11/02 全球购物
以色列的身体护理及家居香薰品牌:Sabon NYC
2018/02/23 全球购物
纽约复古灵感的现代珠宝品牌:Lulu Frost
2018/03/03 全球购物
英国手机零售商:Carphone Warehouse
2018/06/06 全球购物
美国健康和保健平台:healtop
2020/07/02 全球购物
辞职书格式样本
2015/02/26 职场文书
导游词之河姆渡遗址博物馆
2019/10/10 职场文书
spring cloud 配置中心native配置方式
2021/09/25 Java/Android