关于 JavaScript 的 slice 和 splice 方法的一个问题
Posted
技术标签:
【中文标题】关于 JavaScript 的 slice 和 splice 方法的一个问题【英文标题】:A question about JavaScript's slice and splice methods 【发布时间】:2010-12-19 03:51:43 【问题描述】:我遇到了以下代码:
var f = function ()
var args = Array.prototype.slice.call(arguments).splice(1);
// some more code
;
基本上,args
中的结果是一个数组,它是 arguments
的副本,没有第一个元素。
但我不能完全理解的是为什么f
的arguments
(将函数的输入参数保存到类似数组的对象中的对象)对象被传递给slice
方法和slice(1)
如何删除第一个元素(位于索引 0 处)。
谁能帮我解释一下?
附注代码来自这个partial application function
【问题讨论】:
Array.splice(start, deleteCount) 实际上是删除元素,重新索引数组,并更改其长度。 【参考方案1】:linked answer 的实际代码是:
var args = Array.prototype.slice.call(arguments, 1);
即“切片”,而不是“拼接”注>
首先slice
方法常用于make a copy of the array it's called on:
var a = ['a', 'b', 'c'];
var b = a.slice(); // b is now a copy of a
var c = a.slice(1); // c is now ['b', 'c']
所以简短的回答是代码基本上是在模拟:
arguments.slice(1); // discard 1st argument, gimme the rest
但是你不能直接这样做。 special arguments
object(在所有 javascript 函数的执行上下文中可用)虽然是 Array-like,因为它支持通过带有数字键的 []
运算符进行索引,但它实际上并不是一个 Array;你不能.push
上它,.pop
关闭它,或者.slice
它等等。
代码实现这一点的方式是通过“欺骗”slice
函数(在 arguments
对象上同样不可用)以在arguments
的上下文中运行,通过Function.prototype.call
:
Array.prototype.slice // get a reference to the slice method
// available on all Arrays, then...
.call( // call it, ...
arguments, // making "this" point to arguments inside slice, and...
1 // pass 1 to slice as the first argument
)
Array.prototype.slice.call(arguments).splice(1)
完成同样的事情,但对splice(1)
进行了无关调用,该调用从Array.prototype.slice.call(arguments)
返回的数组中删除 元素,该数组从索引1
开始并一直持续到末尾的数组。 splice(1)
在 IE 中不起作用(从技术上讲,它缺少第二个参数,告诉它删除 IE 和 ECMAScript 需要多少项)。
【讨论】:
对不起代码差异,但我从我在这个问题中链接到的答案中复制了我粘贴在这里的代码***.com/questions/373157/…,但作者同时更改了脚本。再次抱歉 @Crescent Flesh,我将问题中的链接更改为指向原始代码 新月新鲜,在肉体中。 @Andreas,是的,我看到了。我相信我的最后一段也提到了splice(1)
,是吗?
有些事情困扰着我,我必须把它说出来:slice()
应该接受争论。它在今天的所有浏览器中都是无参数的,这就是为什么我把它留在我的答案中。但从技术上讲,最后一个示例 Array.prototype.slice.call(arguments)
应该是 Array.prototype.slice.call(arguments, 0)
(即,将 0 作为第一个参数传递给 slice 函数)。如果省略,它基本上默认为 0(同样,在所有浏览器中)。
这是我最近记忆中代码工作原理的最佳分步详细分类。很棒的东西,谢谢。【参考方案2】:
var args = Array.prototype.slice.call(arguments).splice(1);
首先获取arguments
(*) 的副本,然后从其中删除除第一个项目之外的所有项目(以非标准方式),并将这些项目分配给args
。
生成、更改和丢弃的额外数组是非常多余的。最好说 - 正如您链接到的答案中的版本确实如此:
var args = Array.prototype.slice.call(arguments, 1);
部分函数应用也是function.bind
方法的一个特性,由ECMAScript 第五版标准化。在浏览器实现之前,您可以从this answer 底部选择一个备用的 JS-native 版本。
*:array.slice()
是复制数组的常用习语,array.slice(1)
是取尾部。它可以通过Array.prototype
显式调用,因为arguments
不是一个数组,尽管它看起来就像一个数组,所以没有普通的数组方法。这是 JavaScript 的另一个奇怪错误。
您经常看到人们在不是数组的对象上使用Array.prototype
方法; ECMAScript 第三版标准特意说这对于arguments
类似数组是可以的,但不是,您也可以在其他可能是主机的类似数组上执行此操作对象,例如 NodeList 或 htmlCollection。尽管在今天的许多浏览器中,您可能会在非数组上调用 Array.prototype
方法,但实际上唯一安全的地方是在 arguments
上。
【讨论】:
ES5 现在明确记录了许多 Array.prototype 方法来处理 any 类似数组的对象,因此依靠它继续工作应该是安全的。跨度> 【参考方案3】:拼接的返回值是一个被移除元素的数组, 但原始数组(或类似数组的对象)在拼接索引处被截断。
使用 slice 进行复制会保留原始参数数组, 大概是为了稍后在函数中使用。
在这种情况下,args = [].slice.call(arguments, 1)
可以得到相同的结果
function handleArguments()
var A= [].slice.call(arguments).splice(1);
//arguments is unchanged
var s= 'A='+A+'\narguments.length='+arguments.length;
var B= [].splice.call(arguments, 1);
// arguments now contains only the first parameter
s+= '\n\nB='+B+'\narguments.length='+arguments.length;
return s;
// test
alert(handleArguments(1, 2, 3, 4));
returned value:
//var A= [].slice.call(arguments).splice(1);
A=2,3,4
arguments.length=4
//var B= [].splice.call(arguments, 1);
B=2,3,4
arguments.length=1
【讨论】:
以上是关于关于 JavaScript 的 slice 和 splice 方法的一个问题的主要内容,如果未能解决你的问题,请参考以下文章
javascript中不易分清的slice,splice和split三个函数