Nodejs中JS的slice.call(a,xxx)和a.slice(xxx)有什么区别?
Nodejs中JS的slice.call(a,xxx)和a.slice(xxx)有什么区别?
很不解为啥很多地方都写成slice.call(arr)而不是arr.slice呢? 难道call这种调用是普通调用的更靠近底层的调用方式? 还是有效率上的提升或者其他什么的?
Node.js 中 JS 的 slice.call(a, xxx)
和 a.slice(xxx)
有什么区别?
在 JavaScript 中,slice
方法可以用于数组或类数组对象(如 DOM NodeList 或 arguments 对象)来提取一部分。slice
方法有两种常见的用法:
- 直接使用
a.slice(xxx)
:这是最直接的方式,适用于真正的数组。 - 使用
Array.prototype.slice.call(a, xxx)
:这种方式允许你在非数组对象上使用slice
方法。
示例代码
// 定义一个真正的数组
const arr = [1, 2, 3, 4, 5];
// 使用 arr.slice(xxx)
const slicedArr = arr.slice(2); // 结果为 [3, 4, 5]
console.log(slicedArr); // 输出: [3, 4, 5]
// 定义一个类数组对象(例如 arguments 对象)
function example() {
const args = arguments;
// 使用 Array.prototype.slice.call(args, xxx)
const slicedArgs = Array.prototype.slice.call(args, 1);
console.log(slicedArgs); // 输出: [2, 3]
}
example(1, 2, 3);
区别解释
-
适用范围不同:
a.slice(xxx)
:仅适用于真正的数组。Array.prototype.slice.call(a, xxx)
:适用于任何类数组对象,例如arguments
对象、DOM NodeList 等。
-
语法差异:
- 直接使用
a.slice(xxx)
是更简洁的语法,适合已知对象是数组的情况。 Array.prototype.slice.call(a, xxx)
是一种通用的方法,可以在任意对象上调用slice
方法。
- 直接使用
-
性能考虑:
- 在大多数情况下,性能差异微乎其微。然而,在某些特殊场景下(如处理大量类数组对象),使用
Array.prototype.slice.call
可能会稍微高效一些,因为它避免了类型检查和方法绑定的过程。
- 在大多数情况下,性能差异微乎其微。然而,在某些特殊场景下(如处理大量类数组对象),使用
总结
选择哪种方法取决于你的具体需求。如果你确定对象是一个数组,直接使用 a.slice(xxx)
更简洁;如果需要处理类数组对象,那么 Array.prototype.slice.call(a, xxx)
是更好的选择。
当a没有slice的方法时,就显式地call,相当于套用一个函数;
效率上前者要慢4倍以上
就是说slice.call(a)的时候,如果a没有该方法不会报错而a.slice会报错? 我看一些框架什么的源码很多都用XXX.call的形式,我以为效率会高呢,反而慢啊?
做个测试比较下好了,比如下面这个站点 http://jsperf.com/test-call-vs-apply/3
谢啦 早上自己也稍微做过测试了 小数据量是直接调用性能较好 下午突然被告知要学ruby了…
var o={
'xx':'xx',
'yy':'yy'
}
var ao=[]
ao.push.call(o,'one','two','three','four');
//var o2=o.slice(1,3) Error!
var o2=ao.slice.call(o,1,3)
console.log(o2)//['two','three']
这段代码是不是相当于给o对象加了一个数组属性,然后如果调用数组的方法来操作o的话,只会影响到里面的那个数组属性而不会影响到键值对?
function t1 (obj) {
obj.a = '123123'
}
function t2 () {
this.a = '123123'
}
console.time('1')
for (let i = 0; i < 100000000; ++i) {
t1({})
}
console.timeEnd('1')
console.time('2')
for (let i = 0; i < 100000000; ++i) {
t2.call({})
}
console.timeEnd('2')
简单对比了一下 call 和直接赋值的性能,从运行结果上可以看出 t1 的性能会比 t2 的性能高出差不多1倍,但整体上差距不大,感觉这个还是要结合实际的项目,更多的是考虑项目的结构上的问题吧,采用更加清晰的写法
slice.call(a, xxx)
和 a.slice(xxx)
的主要区别在于它们的使用场景和适用对象。
slice.call(a, xxx)
可以将非数组对象转换为数组切片。例如,如果你有一个类数组对象(如函数的 arguments 对象),你可以使用 slice.call()
将其转换为真正的数组,然后对它进行数组方法操作。
function example() {
const args = arguments;
console.log(args.slice(1)); // TypeError: args.slice is not a function
console.log(Array.prototype.slice.call(args, 1)); // [2, 3]
}
example(1, 2, 3);
a.slice(xxx)
是直接对数组对象 a
调用 slice()
方法,返回一个新的数组,包含从索引 xxx
开始到结束的所有元素。
const a = [1, 2, 3, 4];
console.log(a.slice(1)); // [2, 3, 4]
总结来说,slice.call(a, xxx)
更通用,可以处理非数组对象;而 a.slice(xxx)
直接作用于数组对象,语法更简洁。