在JS中,哪个更快:Object的"in"运算符或Array的indexof?

Fis*_*ter 35 javascript performance

我想保留一个字符串列表,我只会检查它是否存在,例如:

corporatePlan = [
    'canDeAuthorize',
    'hasGmailSupport',
    'canShareReports',
    'canSummonKraken',
    'etc'
]
Run Code Online (Sandbox Code Playgroud)

因此,当用户试图召唤海妖时,我会corporatePlan.indexof('canSummonKraken') != -1看看他是否可以.

同事建议将它作为对象存储会更快:

"Corporate Plan" = {
    'canDeAuthorize' : null,
    'hasGmailSupport' : null,
    'canShareReports' : null,
    'canSummonKraken' : null,
    'etc' : null
}
Run Code Online (Sandbox Code Playgroud)

并且只'canSummonKraken' in corporatePlan需要检查计划是否包含该密钥.这在经典的CS意义上是有意义的,因为当然"包含"是地图上的恒定时间和数组上的线性.这会检查数组和对象是如何在JS中引入的吗?

在我们的特殊情况下,使用少于100个元素,速度并不重要.但是对于更大的阵列,访问哪种方式会更快?

T.J*_*der 27

在JavaScript中,您通常需要处理各种各样的实现(除非您在受控环境中使用它,例如您选择引擎的服务器),因此特定性能问题的答案往往是"它取决于,检查你将要使用的引擎." 在一个实现上最快的可能在另一个实现上更慢等等.http://jsperf.com对于这类事情很方便.

那就是说,我希望in在这里成为一个明显的赢家.Array#indexOf必须在搜索中访问数组索引,并且数组索引是与任何其他属性一样的属性.因此访问数组索引0以查看它是否是所需的字符串需要查找,0就像其他需要查找属性一样"canSummonKraken"(然后它必须在之后进行字符串比较).(是的,数组索引是属性.JavaScript中的数组根本不是数组.)并且indexOf可能必须在搜索期间访问多个属性,而in只需访问一个.但同样,你需要在你的目标环境中检查它以确定,一些实现可以优化具有连续索引范围的数组(但最慢的那些肯定不会,当然如果你担心速度,你我担心最慢的引擎上的速度最快,比如IE.

另请注意,并非所有JavaScript引擎都有Array#indexOf.大多数人都这样做,但仍然有一些较老的人(我看着你,微软)没有.

您还有使用in或是否使用的问题hasOwnProperty.使用in的优点是它是一个操作符,而不是函数调用; 使用hasOwnProperty的优点是它只会查看特定的对象实例,而不是它的原型(及其原型等).除非你有一个非常深刻的继承层次结构(并且你没有在你的例子中),我打赌in胜利,但记住它确实检查层次结构是有用的.

此外,请记住,"canSummonKraken" in obj在您显示的示例对象文字中将是如此,因为该对象确实具有该属性,即使该属性的值为null.你必须没有财产在返回false.(而不是in,您可能只使用true和false并将其查找为obj.canSummonKraken.)

所以你的选择是:

  1. 你的数组方法:

    corporatePlan = [
        'canDeAuthorize',
        'hasGmailSupport',
        'canShareReports',
        'canSummonKraken',
        'etc'
    ];
    
    console.log(corporatePlan.indexOf("canSummonKraken") >= 0);  // true
    console.log(corporatePlan.indexOf("canDismissKraken") >= 0); // false
    
    Run Code Online (Sandbox Code Playgroud)

    ......我不推荐.

  2. in方法:

    corporatePlan = {
        'canDeAuthorize'  : null,
        'hasGmailSupport' : null,
        'canShareReports' : null,
        'canSummonKraken' : null,
        'etc'             : null
    };
    
    console.log("canSummonKraken" in corporatePlan);  // true
    console.log("canDismissKraken" in corporatePlan); // false
    
    Run Code Online (Sandbox Code Playgroud)

    可能比indexOf它快,但我会测试它.如果列表可能很长并且你将要拥有很多这些对象,那么它很有用,因为它只需要存在"truthy"属性.空对象表示用户无法执行任何操作的计划,并且非常小.

    我应该在这里注意两件事:

    1. in也检查对象的原型,所以如果你有像toString或那样的设置valueOf,你会得到误报(因为这些属性几乎都是所有对象都来自Object.prototype).在支持ES5的浏览器上,您可以通过使用null原型创建对象来避免此问题:var corporatePlan = Object.create(null);

    2. 也许是因为它检查原型,in操作员在一些引擎上出乎意料地慢.

    这两个问题都可以通过使用hasOwnProperty来解决:

    console.log(corporatePlan.hasOwnProperty("canSummonKraken"));  // true
    console.log(corporatePlan.hasOwnProperty("canDismissKraken")); // false
    
    Run Code Online (Sandbox Code Playgroud)

    有人会认为运算符比方法调用更快,但事实证明,跨浏览器并不可靠.

  3. 标志方法:

    corporatePlan = {
        'canDeAuthorize'   : true,
        'hasGmailSupport'  : true,
        'canShareReports'  : true,
        'canSummonKraken'  : true,
        'canDismissKraken' : false,
        'etc'              : true
    };
    
    console.log(corporatePlan.canSummonKraken);  // "true"
    console.log(corporatePlan.canDismissKraken); // "false"
    
    // or using bracketed notation, in case you need to test this
    // dynamically
    console.log(corporatePlan["canSummonKraken"]);  // "true"
    console.log(corporatePlan["canDismissKraken"]); // "false"
    
    // example dynamic check:
    var item;
    item = "canSummonKraken";
    console.log(corporatePlan[item]);  // "true"
    item = "canDismissKraken";
    console.log(corporatePlan[item]);  // "false"
    
    Run Code Online (Sandbox Code Playgroud)

    ......这是一种相当正常的方式,可能比它快in,并且可能至少和它一样快hasOwnProperty.(但请参阅我的开头段落:在您的环境中测试.:-))


onc*_*ode 15

我测试了它:http://jsperf.com/array-indexof-vs-object-s-in-operator/4

找到第一个元素时,两者都有很好的结果,具体取决于使用的浏览器.因此,找到最后一个元素,in运算符要快得多.

但后来我使用了一个带有typeof运算符的变体,它比两者都快得多:

if (typeof obj['that'] !== "undefined") {
  // found
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么`typeof!=='undefined'`,而不是`!== undefined`? (8认同)
  • @oncode在现代浏览器中已不再适用; 更重要的是,这开始时完全是偏执狂.typeof代码看起来更复杂. (6认同)
  • `undefined`不是常量,可以被覆盖.检查"未定义"是更安全的. (2认同)

Juz*_*Ali 11

这是一个基准http://jsperf.com/array-indexof-vs-object-keys.在chrome和firefox中,检查对象中键的存在比扫描数组快100%.

结果

但是如果考虑初始化时间,差异会消除,对象会比数组花费更多时间进行初始化.

在此输入图像描述