Rumah > Soal Jawab > teks badan
今天看到这个用法的时候产生了疑问,
slice 方法可以用来将一个类数组(Array-like)对象/集合转换成一个数组。你只需将该方法绑定到这个对象上。
mdn上给出了一个例子:
function list() {
return Array.prototype.slice.call(arguments);
}
var list1 = list(1, 2, 3); // [1, 2, 3]
我的问题是:
平时更容易遇到fun.call (null, arguments)
这样的用法,因为Function.prototype.call()的用法是
fun.call(thisArg[, arg1[, arg2[, ...]]])
所以遇到把Array.prototype.slice.call(arguments)
这样的把arguments作为在函数运行时指定的this值感觉很别扭,总是想成Array.prototype.slice.call(null, arguments)
这样的,又不知道这样为什么不对?
除了Array.prototype.slice.call(arguments)
这样的用法,那么Array.prototype上其他的方法是不是也可以这样使用呢?比如Array.prototype.splice.call(arguments,1)
?
ringa_lee2017-04-11 12:27:57
我分享一下我的想法吧,仅供参考:
第一个问题:
在js中用call
去掉用函数传的的一个参数就是调用这个函数的对象(即被调用函数的this
指向),应了这句this
谁调用它就指向谁。然后第二个参数开始就是传入函数里的参数。
在你上面的代码中:Array.prototype.slice.call(null, arguments)
相当于是用null
去调用slice
函数,把arguments
作为函数的参数。null
是调用不了这个slice
函数的因为null
既不是数组也不是类数组,所以会报错。
第二个问题:
可以的,如下图:
最后附上个链接(翻到文章最下面的小拓展部分)
PHP中文网2017-04-11 12:27:57
Array.prototype.slice.call(arguments)
这里其实是把arguments
设置成函数slice
的this
,也就是对arguments
进行slice
操作,从而达到把传入的参数变成array
的目的。而Array.prototype.slice.call(null, arguments)
其实是null.slice(arguments)
, 这个就会throw TypeError
了吧
PHP中文网2017-04-11 12:27:57
这个问题分成两部分解释
为什么使用call
你已经了解到
Function.prototype.call()的用法是
/*
* 分析传入参数的作用
* this: 设置func中的上下文/this值
* args*: 传入的参数
*/
func.call(this[, args1[, args2[, args3]]]);
另外还知道slice的相关用法
slice 方法可以用来将一个类数组(Array-like)对象/集合转换成一个数组。你只需将该方法绑定到这个对象上。
OK,(敲黑板)(划重点)这里使用call并不是那么符合语境的(摔),应该使用绑定
Array.prototype.slice.~~绑定~~bind(arguments)
其本质和
Array.prototype.slice.call(arguments);
是一样的,之所以这样使用,是因为
arguments.slice();// 这样写报错。。。arguments并没有slice方法
// 那么我们如何令arguments能够调用slice方法呢?
// 正常情况下是一个数组对象var arr = [1, 2, 3]来进行调用
// arr.slice() // [1, 2, 3] 正确,然而没什么用
// 我们知道,是数组arr调用的slice方法,这个调用方,我们称他为上下文
// 接下来就简单了,这就是为什么要用call/bind的原因
arguments是什么,什么叫类数组对象
arguments: 全称Function.prototype.arguments(有的地方说是有区别,求哪位大神明示。)
arguments完全不是一个数组,虽然多多少少有点像。在很多情况下,尽管不是,我们还是希望把它当作数组来处理。把arguments转换成一个数组
apply: 第二个参数可以直接使用类数组对象
callee: 可以通过arguments的callee方法找到arguments的所在方法(如果觉得这句话比较晕,可以忽略)
其实除去arguments外,还有一些类数组对象,举个栗子
var arr_like = {'0':'Mike', '1': 'Joy', '2': 'Brown', lenght: 3};// lenght属性很重要,计数要从0开始,记得要加引号,纯数字或以数字开头的属性都要写成字符串的形式,取值时也要加引号(纯数字可以不加)
Array.prototype.slice.call(arr_like); // ['Mike', 'Joy', 'Brown'];
Array.prototype.join.call(arr_like, ' love ');// "Mike love Joy love Brown"
这就是一个简单的类数组对象啦。
说的比较杂,希望能帮到你一二
PHPz2017-04-11 12:27:57
谢邀。以下是我个人的理解。如果有错误请指正。
首先一点,你可能已经知道了,.slice
是数组方法,可以用来深拷贝数组。如果直接赋值就是浅拷贝
然后,看下 arguments
长啥样儿的就懂了。。JS 中,两种常见的 "array-like object"(像数组一样的对象)一个是 arguments
,一个就是 nodeList
。
他们长这样:
var obj = {
'0': 'a',
'1': 'b',
'2': 'c',
'3': 'd',
length: 4
}
如果一个东西满足这两点:
有数字形式的 key
,从 0 开始
有一个 length
属性
那么这个东西就是 "array-like object"。"array-like object" 至少有一个好处,就是可以直接构建一个 Array
实例。可以通过 Array.from()
或者 ES6 的 "Spread Operator"(也就是 ...
)来构建。
注意:JS 中只允许字符串作为对象的 key
,因此才会是上面的写法。就算你尝试着用数字去做 key
,它也会帮你转成字符串的。
由于这个东西本身还是 object
,或者说它不是 Array
的一个 instance
(实例),因此,没法直接调用 .slice
方法。
Array.prototype.slice
返回的是一个 Function
实例,调用它的 call
方法是为了改变 .slice
方法的 this
,也就是说,改变一下谁来调用 slice
。
因此,.call(arguments)
这个写法并不比别扭。你如果第一个参数传入 null
是肯定不行的,因为 null
既没有 .slice
方法,也不能构建成一个 array
。"array-like object" 虽然也没有 slice
方法,但至少它有上面说到的 "数字key" 和 "length" 属性,因此可以构建一个 array
个人看来,不妨把它简单理解为:
Array.prototype.slice(arguments)
做的事儿就是:
var temp = Array.from(arguments)
temp.slice()
至于你提到的 Array.prototype.splice.call(arguments,1)
,没有问题。把 arguments
作为 this
,就用 arguments
构建一个 Array
实例,也就有了 splice
方法。不妨也把它理解成:
var temp = Array.from(arguments);
temp.splice(1)
黄舟2017-04-11 12:27:57
谢邀,感觉楼上兄弟们回答的都很好。
先说一下[].slice(start, end)
接收的参数,start
为开始索引,end
为结束索引,而且取前不取后,如果省略参数,则拷贝一个数组的副本。
前面你也说了call
的用法,fn.call(thisArgthisArg[, arg1[, arg2[, ...]]])
;
下面我们用call调用slice方法:对应开始填参数————第一个为要截取的对象(arguments对象),第二个为开始索引,第三个参数为结束索引。
var slice = Array.prototype.slice;
slice.call(arguments, start, end);
下面我们省略start和end
Array.prototype.slice(arguments);
类似的,我们使用document.getElementsByTagName获得的也是一个类数组,我们可以把他转为原生数组
var list = [].slice.call(documengetElementsByTagName('p'));
我感觉你是自己对于数组的方法没有深入的理解,而不是call的用法,理解好数组方法的各个参数的意义,对应着填到call或者apply的参数位置,也就好理解了。