【问题标题】:[].slice or Array.prototype.slice[].slice 或 Array.prototype.slice
【发布时间】:2012-02-18 20:43:48
【问题描述】:

我遇到了将 Array 原型应用于原生对象的两种方法:

arr = Array.prototype.slice.call(obj);
arr = [].slice.call(obj);

以类似的方式,获取原生类数组对象的真实类型:

type = Object.prototype.toString.call(obj);
type = {}.toString.call(obj);

一个简单的测试:

function fn() {
    console.log(
        Array.prototype.slice.call(arguments),
        [].slice.call(arguments),
        Object.prototype.toString.call(arguments), 
        {}.toString.call(arguments)
    );
}

fn(0,1);

小提琴:http://jsfiddle.net/PhdmN/

他们看起来和我一模一样;第一种语法使用得更频繁,但第二种语法肯定更短。使用较短的语法有什么缺点吗?

【问题讨论】:

  • 第二种语法不必要地创建了一个新对象。
  • @DanD.,您应该将此作为答案发布,因为它是正确答案。 ;)

标签: javascript arrays object syntax prototype


【解决方案1】:

它们在功能上是相同的。

但是,Array 对象可以被覆盖,导致第一个方法失败。

//Example:
Array = {};
console.log(typeof Array.prototype.slice); // "undefined"
console.log(typeof [].slice);    // "function"

文字方法创建Array 的新实例(与Array.prototype. 方法相反)。两种方法的基准测试:http://jsperf.com/bbarr-new-array-vs-literal/3

当你要多次使用该方法时,最好的做法是缓存该方法:

  • var slice = Array.prototype.slice; //Commonly used
  • var slice = [].slice; - 如果您担心 Array 的存在,或者您只是喜欢较短的语法。

【讨论】:

  • 不,只有结果相同。创建新对象不一样,并且显式使用原型也更快,因为它需要运行时更少的工作来确定方法所在的位置。两者都微不足道,但如果它们同样易于使用,为什么不寻求更好的解决方案?
  • @Lucero 它们在功能上是相同的。 [].slice 确实初始化了一个新实例(几乎不影响性能)。 Array 方法更简洁,但在重新定义 Array 时会失败,
  • 在 JS 中可以破坏很多东西。如果 Array.prototype.slice 被更改,那么这两个变体都不会按预期运行。让我想起了重新定义的 undefined... 无论如何,创建对象并不昂贵,但考虑到垃圾收集的成本,它可能会形成一个紧密的循环。
  • @Lucero 两全其美:缓存变量,使用[].slice :)
  • 如果您对某人覆盖Array 有一些非理性的恐惧,您甚至可以使用Object.getPrototypeOf([]).slice。等等,如果有人覆盖Object 怎么办? ... ;)
【解决方案2】:

这是一个有趣的问题!让我们总结一下每种选择的优点(✔️)和缺点(❌):

[].slice

  • ✔️:打字速度更快
    两次击键,没有 shift 修饰符或任何东西,
    你的 linter 知道 [.slice 是一个错字。
  • ✔️:阅读速度更快
    您可以更快地识别相关部分 (slice)。
  • ✔️:更受欢迎
    56M+ snippets on GitHub(截至 2018 年底)。
  • ✔️:不能被覆盖
    Rob's answer 的第一部分完美地展示了这一点。
  • ✔️:跑得更快。
    等等,什么?嗯,这实际上就是这个答案的重点。

与您几乎在所有地方的想法和阅读相反,[].slice.call(...) 确实实例化一个新的空Array 只是为了访问它的slice 属性!强>。

如今(5 年多来 - 截至 2018 年底),JIT 编译 (1) 包含在您运行 JavaScript 的任何地方(除非您'仍在使用 IE8 或更低版本浏览网页)。

这种机制允许 JS 引擎:(2)

... 直接解析[].slice静态,一次性直接作为Array.prototype 引用,并且只有一个可配置的属性访问:forEach

Array.prototype.slice

  • ❌:输入速度较慢
    在您尝试运行代码之前,拼写错误(例如:Array.prorotype.slice)看起来不错。
  • ❌:不太受欢迎
    8M+ snippets on GitHub(截至 2018 年底)。
  • ❌:运行速度较慢
    Array.prototype.slice 是:(2)

... 查找 整个作用域 以获取 Array 引用,直到所有作用域都遍历到 global 一个... 因为您可以命名变量Array 任何时候都可以。

一旦到达全局范围并找到原生对象,引擎就会访问它的原型,然后访问它的方法
...
O(N) 范围分辨率 + 2 个属性访问(.prototype.forEach)。

  • ✔️:允许您无缝适应任何编码约定,这些约定会严格阻止您以([` 开头的行
    绝对是一件好事(讽刺地)。
  • ✔️:您不必解释为什么 [].slice 在几乎所有方面都更好。
    虽然现在,这只能归结为下面的clicking the share link ?

免责声明

请注意,实际上,两者的实际运行速度都。这不是您的应用程序的瓶颈。


  1. 您可能想阅读A crash course in just-in-time (JIT) compilers
  2. 引自 Andrea Giammarchi(Twitter 上@WebReflection

【讨论】:

  • 顺便说一句,这一切都已经过时了。正确、现代(直观易懂)的 ES6 方式是 Array.from
  • @rugk 好吧,对于大型数组输入,我倾向于避免不必要地使用 Array.from
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-27
  • 2018-12-05
  • 2012-05-19
  • 2020-12-31
  • 2020-11-10
  • 1970-01-01
  • 2020-01-04
相关资源
最近更新 更多