javascript - 如何理解Array.prototype.slice.apply({0:1,length:1});
大家讲道理
大家讲道理 2017-04-10 14:59:41
[JavaScript讨论组]

这个结果是把{0:1,length:1}这个对象转成[1]

我的理解apply的第一个参数是 调用slice
的对象,

可是slice不是数组的方法么,对象怎么能调用?
还有这个slice方法都没传参数,

我想知道怎么实现这个对象转数组的

大家讲道理
大家讲道理

光阴似箭催人老,日月如移越少年。

全部回复(6)
阿神

slice可以处理array-like object,即这个object可以.length并且可以通过数字下标取到相应的值时候,slice就会像处理对象一样处理。解释

阿神

javascript中类似“length属性存放长度,0开始的整数key存放数据”的对象很多场景下都可以被视作数组(array-like objects)。内置的多数(未验证是否所有)数组方法都是可以作用于任何array-like object上的。比如push也有类似的行为

(注意因为undefined被视为0,所以甚至连length属性都没有的时候也一样能工作)

也就是这些数组的内置方法其实只依赖length指示长度和整数下标存放内容而已,这是弱类型语言常见的“鸭子类型”思想

常用slice,或者说slice有转换的效果,是因为slice的行为不是修改原有的对象(数组),而是新建一个数组存放slice的结果。至于不传参数默认0之类的,就是默认参数呗

PHPz

对象不是直接调用slice方法,而是通过apply,将slice方法中的this指向该对象。
JavaScript中的数组也可以看成是这样的对象

var array = [1, 2, 3];
var obj = {
    0: 1,
    1: 2,
    2: 3,
    length:3
}

注意了,这个length属性很重要,有了length就可以像数组一样遍历这个对象了。

再来实现一个简单的slice方法,

function slice(start, end) {
    var array = [];
    start = start ? start : 0;
    end = end ? end : this.length;

    for (var i = start, j = 0; i < end; i++, j++) {
        array[j] = this[i];
    }

    return array;
}

例如楼主举例的数据,代入方法中一步步执行下,就明白怎么回事了。
说白了这个对象{0:1,length:1}在这种情况下可以看成[1]

Array.prototype.slice.apply({0:1,length:1});
在这种情况下就相当于

var array=[1];
array.slice();
天蓬老师

先假定楼主理解Array.prototype.slice.apply({0:1,length:1});中的Arrayslice

然后只要理解prototypeapply还有Array与object之间的关系的就行了。(最后还有this的说明)

prototype

js是面向对象的,所有函数都有它的属性,和prototype,例子

//代码片段1
function Array(){
    this.length = 5;
}
Array.prototype.slice = function(){}
//上面的函数名,属性名,均直接使用了和数组一样的名字,这样好理解。

其中this.length是方法Array的属性,我们要获取这个值可以这样

//代码片段2
var a = new Array();
console.log(a.length);//5
//要调用Array()的方法slice,可以使用:
a.slice();

结论:看了上面的用法,是不是和平时使用的数组很像?其实js的Array就是用与代码片段1差不多的方法写的,所以a.slice()是一个函数,所以Array.prototype.slice()Array的一个方法,只是这个方法放在Array.prototype里。

prototype可以给一个函数定义一个子方法,该子方法能拿到函数的所有属性。(ps.你知道,slice()必须知道一个已知的数组才能返回选定的元素的吧?但是这个已知的数组却没有作为参数传递给slice(),这时slice()要怎么才知道要从哪个已知数组返回元素?答案是在slice()中使用this拿到当前数组的所有元素。因为在Array()肯定有一个或者多个属性,是保存着数组的所有元素的。)

apply

是所有函数都具有的方法,就像所有Array都有slice方法一样,只要在函数后加上.apply()就能用了。这个方法的功能是调用函数,并且可以修改函数内的this和传入函数的参数。

先说说apply()的参数,有两个,第一个用于修改函数内的this,第二个参数是数组,数组中的每个项都是传到调用apply()的函数中的参数,相当于函数中的arguments。

Array.prototype.slice()中,this是指Array(),如果实例化过Array()var a = new Array();)则是指a,也就是一个数组。

所以Array.prototype.slice.apply(a,[])等于a.slice()
所以Array.prototype.slice.apply([1]);等于[1].slice()等于var a=[1]; a.slice()

Array与object之间的关系

你会发现下面这个有趣的事情

var a=[1,2];
console.log(typeof a);//object

其实数组是一个特殊的object对象,[1,2]约等于{0:1,1:2,length:2},这里是约等于哦,因为直接使用var a={0:1,1:2,length:2}实例化的是Object,不是Array是不能用数组的专用方法的哦,如pushslice,会提示undefined is not a function是找不到此方法的意思。

但是此方法本身是可以处理这种格式的“数组”的,只是这个方法不在Object下,也不在Object.prototype下而已,所以不能使用a.slice(),所以才有了通过prototype直接访问slice方法,再使用apply重新指向它的this,就可以使用slice了。

this

我以前也是不理解this是什么东西,好像在不同地方有不同的用法一样,但是现在发现,其实就只有一种用法,往细了来说,最多两种。

下面括号中的一段删除,因为我发现我错了,this的理解看来不是我想的那样,抱歉,但是用法是没错的
(this,可以把它看做是函数的一个隐藏参数、默认参数,默认情况下该参数等于此函数,即:

function a(this){console.log(this)}
a();
//可以自己试试输出的是什么,试的时候去掉参数位置的this

当this为默认值的时候,可以说它的功能就是给该函数添加属性,以及访问该函数的属性。)

而如果该函数是在其它函数(后面称为a函数)的prototype内,那this指的是a函数,也可以是该函数,也可以是其它a函数prototype内的其它函数,因为这时候定义的属性在其它prototype内的函数都能访问。

那么问题来了,使用jquery event的时候,回调函数内的this为什么指代的是触发事件的DOM?实质上,只要使用apply(),你可以把函数内的this参数改为任何东西。

最后再结合对象来说,一个函数可以看作是一个对象,this在默认情况下指的就是这个对象的意思,this在哪个对象内,指的就是哪个对象。所以可以给对象添加属性,方法。

迷茫

楼上说得有点复杂了,我试着简单的说下:
slice的参数为(start, [.end]),start为必需
看再楼主的题目:
Array.prototype.slice.apply({0:1, length:1})
也就是说其实slice方法是没有传参数的
那么start就是undefined
slice方法中如果没有设置start,start就是0,可通过如下证明
[1,2].slice(); // [1,2]
end如果没有指定,就是当前对象的length属性的值,也就是1
那么结果就是{0:1}.slice(0, 1); // 这是伪代码哈
返回一个新的数组,从对象中0开始,到1结束,也就是取对象下标为0的值。
{0:1}[0] => 1;
所以返回[1]
如果这样写
Array.prototype.slice.apply({0:1, length:3})
结果就应该是[1, undefined, undefined]

高洛峰

楼上几位回答很不错,但说的太细可能会让楼主略感迷茫...我来个简化版的

Array.prototype.slice

数组的切割方法,它返回的是一个被切割数组的副本,例如:

javascript  [0,1,2].slice();//[0, 1, 2]
  [0,1,2].slice(0);//[0, 1, 2]
  [0,1,2].slice(0,1);//[0]

注意,它返回的是一个被切割的数组的副本

apply

applycall是把一个方法借给另外一个对象,最著名的就是类型判定:

javascript(1).toString();//"1"
Object.prototype.toString.call(1);//[object Number]

slice是通用的,这个通用的是如何定义的呢?
因为数组本身就是特殊的对象,那么数组的方法也可以借给一些和数组行为相似对象。当一个对象拥有和数组一样的特性,那么就可以使用slice

javascript['a','b'].slice(1);//["b"]
Array.prototype.slice.call({'0':'a','1':'b',length:2},1);//["b"]
  • 对象的属性名和数组的索引对应。
  • 对象拥有和数组同名同特性的length。

那么这个对象就拥有了和数组相似的特性,就可以使用Array的通用方法slice
本质上,楼主的代码,实现的就是apply就是把数组的slice(),借给拥有和数组一样特性的对象。

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号