【问题标题】:[].slice.call(this) vs array.prototype.call(this)[].slice.call(this) vs array.prototype.call(this)
【发布时间】:2014-12-05 01:05:44
【问题描述】:

只是想知道下面的 js 脚本有什么不同。

[].slice.call(this) vs Array.prototype.slice.call(this);

他们似乎也在做同样的事情,有人能解释一下不同之处吗?我应该坚持哪一个?

干杯

【问题讨论】:

  • 看来你打错了; Array,不是array,对吧?
  • Array.prototype.call 不正确。也许你的意思是Array.prototype.slice.call()
  • 对不起,我错过了切片
  • 由于没有明确提及:Array.prototype.slice === [].slice。它是同一个函数,只是获取引用的两种不同方式。
  • 顺便说一句,现代(直观易懂)的 ES6 方法是 Array.from

标签: javascript


【解决方案1】:

它们几乎相同。让我们逐一检查:

[].slice.call(data)

它有什么作用?

  • [] - 这将创建新的数组,与 new Array() 相同
  • slice - 它从数组中检索方法 slice
  • call(data) - 它调用slice() 方法用data 变量替换其当前上下文,即使用data 作为其内部数组,而不是[]。这将返回我们的data 转换为Array

现在,第二个:

Array.prototype.slice.call(data)

这个:

  • Array.prototype.slice - 从 Array.prototype 检索方法 slice;简而言之 - 它会在没有任何上下文(内部数据)的情况下返回 slice 方法。
  • call(data) - 与之前的变体一样,以 data 作为其上下文调用此方法。

结论

[].sliceArray.prototype.slice 都返回一个 slice 函数,您可以在某个数组上调用该函数,然而此数组不是作为参数传递,而是作为上下文传递(使用 call函数对象的方法)。在 JavaScript 中,这些调用是完全一样的:

// Calling as a method of 'Hello' string
'Hello'.indexOf('e') // returns 1

// Calling as unbound method
String.prototype.indexOf.call('Hello', 'e') // returns 1
String.prototype.indexOf.apply('Hello', ['e']) // returns 1

这些方法几乎相同。第一个更具可读性,但第二个使用较少 bit 的内存,因为它不会创建临时初始 Array

【讨论】:

  • 感谢安德鲁这很有意义
  • @bluebill1049 另一个有趣的补充:如果你调用[].slice(),它将返回一个空数组[],如果你调用[1,2,3].slice(),则返回[1,2,3]。而且,另一方面,直接调用Array.prototype.slice()(没有.call)总是会返回[],因为它没有内部上下文,它有点像“静态方法”。
  • 很好的例子 :) 第二个更好
  • @AndrewDunai 我只是想强调一个事实,slice 总是返回一个新数组。所以调用 slice 也是一个数组构造。此外,内存使用并不是真正的症结所在,但构建和垃圾收集这些数组的 CPU 时间在高性能应用程序中可能会出现问题。
  • “直接调用 Array.prototype.slice() ... 将始终返回 [],因为它没有内部上下文” 这并不完全正确。在这种情况下,this 将引用Array.prototype。碰巧Array.prototype.length0。这就是你得到一个空数组的原因。
【解决方案2】:

我相信Array 实际上并没有创建对象,而[] 是数组的一个实例。

【讨论】:

    【解决方案3】:

    一定要坚持使用后者,因为第一个是隐式数组构造,与:

    new Array().slice.call(this)

    它正在构建一个新数组,因为您不使用它,所以之后需要对其进行垃圾收集。虽然这两个语句都“工作”,但上面提到的做了很多额外的工作,首先你构造一个新实例,然后查找实例本身是否具有 slice 属性,因为这是错误的 prototype 链被遍历在Array.prototype 上找到slice,然后在called 上找到。然后你用你的另一个数组作为作用域来调用它,所以基本上用你的另一个数组来渲染你创建的实例。

    这就是为什么Array.prototype.slice.call(myarr) 是访问slice 方法的正确 方式。

    【讨论】:

    • 哎呀我没有给-1,请说明投反对票的原因
    【解决方案4】:

    Array.prototype.slice.call() 似乎性能略高一些,尽管这是有道理的,因为在运行时“查找”此方法会更快。我认为[].slice.call() 是最好的选择。 Here's the jsperf of reference

    让我们说实话,在什么情况下,两者之间的微不足道的差异会成为网站性能不佳的主要原因?实际上,听起来像天堂。文字方法的较短语法很棒。我宁愿为自己节省半秒来键入原型变体,也不愿提高效率。

    Array.prototype 的棺材钉... 有人说这是不负责任的,因为你冒着改变它的风险。但是……这太愚蠢了。图 1:Array.prototype = function() { console.log('foo') }; 哎呀...... 这可能一直都在发生。 说真的,即使授予其合法性仍然完好无损,我需要更长的时间才能打字并且是与它更性感的字面姐妹相比,imo 是可怕的。

    您真正问题的真正答案是功能完全相同。使用您在临终时仍会欣赏的任何一种。

    【讨论】:

    • 谢谢,@bluebill1049!我喜欢你的别名,即使它有数字,而且数字很难。
    • “有人说这是不负责任的,因为你冒着改变它的风险” 我想知道那些人是谁。我认为在这种情况下,如果你想要的只是 call 它,那么“意外”分配一个属性是相当困难的。
    • 完全正确。敷衍参考:stackoverflow.com/questions/9006553/…
    • Object.getPrototypeOf([]).slice.call() 一个愉快的妥协?
    猜你喜欢
    • 2023-02-22
    • 1970-01-01
    • 2014-10-11
    • 2014-05-04
    • 1970-01-01
    • 2012-10-18
    • 1970-01-01
    • 1970-01-01
    • 2011-04-26
    相关资源
    最近更新 更多