Nodejs中JS的slice.call(a,xxx)和a.slice(xxx)有什么区别?

Nodejs中JS的slice.call(a,xxx)和a.slice(xxx)有什么区别?

很不解为啥很多地方都写成slice.call(arr)而不是arr.slice呢? 难道call这种调用是普通调用的更靠近底层的调用方式? 还是有效率上的提升或者其他什么的?

9 回复

Node.js 中 JS 的 slice.call(a, xxx)a.slice(xxx) 有什么区别?

在 JavaScript 中,slice 方法可以用于数组或类数组对象(如 DOM NodeList 或 arguments 对象)来提取一部分。slice 方法有两种常见的用法:

  1. 直接使用 a.slice(xxx):这是最直接的方式,适用于真正的数组。
  2. 使用 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);

区别解释

  1. 适用范围不同

    • a.slice(xxx):仅适用于真正的数组。
    • Array.prototype.slice.call(a, xxx):适用于任何类数组对象,例如 arguments 对象、DOM NodeList 等。
  2. 语法差异

    • 直接使用 a.slice(xxx) 是更简洁的语法,适合已知对象是数组的情况。
    • Array.prototype.slice.call(a, xxx) 是一种通用的方法,可以在任意对象上调用 slice 方法。
  3. 性能考虑

    • 在大多数情况下,性能差异微乎其微。然而,在某些特殊场景下(如处理大量类数组对象),使用 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) 直接作用于数组对象,语法更简洁。

回到顶部