为什么Javascript==/==字符串相等有时具有恒定的时间复杂度,有时具有线性时间复杂度?

为什么Javascript==/==字符串相等有时具有恒定的时间复杂度,有时具有线性时间复杂度?,javascript,string,performance,time-complexity,string-interning,Javascript,String,Performance,Time Complexity,String Interning,在我发现常见/最新的Javascript实现使用字符串Interning来实现性能提升()之后,我认为字符串的==将获得恒定的O(1)时间。所以我对这个问题的回答是错误的: 因为根据这个问题的OP,它是O(N),所以将字符串输入加倍会使相等所需的时间加倍。他没有提供任何jsPerf,所以需要更多的调查 所以我使用字符串实习的场景是: var str1=“stringwithmillionchars”//存储在地址51242中 var str2=“stringwithmillionchars”/

在我发现常见/最新的Javascript实现使用字符串Interning来实现性能提升()之后,我认为字符串的
==
将获得恒定的O(1)时间。所以我对这个问题的回答是错误的:

因为根据这个问题的OP,它是O(N),所以将字符串输入加倍会使相等所需的时间加倍。他没有提供任何jsPerf,所以需要更多的调查

所以我使用字符串实习的场景是:

var str1=“stringwithmillionchars”//存储在地址51242中

var str2=“stringwithmillionchars”//存储在地址12313中

“stringwithmillionchars”将存储一次,比如说存储在内存的地址201012中 str1和str2都指向这个地址201012。然后可以通过某种散列来确定该地址,以映射到内存中的特定位置

所以当你做

“stringwithmillionchars”==“stringwithmillionchars”

看起来像

getContentOfAddress(51242)==getContentOfAddress(12313)

201012==201012

这需要O(1)/恒定时间

JSPerfs/性能更新:

即使字符串长16倍,JSPerf似乎也显示常量时间??请看一看:

可能上面的字符串太小: 这可能显示线性时间(感谢sergioFC),字符串是用循环构建的。我尝试不使用函数-仍然是线性时间/我稍微改变了一下

根据(sergioFC制作的12MB文件),当您有一个字符串并且已经在引号中赋值时,无论t1和t2有多大(例如5930496个字符),都需要0-1ms/瞬间

似乎当您使用for循环或函数构建字符串时,该字符串就不会被插入。因此,只有当您直接分配一个带引号的字符串时,才会发生实习,如
var str=“test”

根据,即使要比较的对象的类型是字符串,也会检查所有字符是否相等

  • 如果
    Type(x)
    是字符串,则返回
    true
    如果
    x
    y
    是完全相同的字符序列(相同的长度和相应位置的相同字符)
    否则,返回
    false

  • 实习严格地说是一种实施,是为了提高绩效。语言标准在这方面没有任何规定。因此,是否插入字符串取决于规范的实现者。

    首先,最好看到一个JSPerf测试,它演示了字符串大小加倍会使执行时间加倍的说法

    接下来,让我们认为这是理所当然的。这是我的理论(未经证实,未经检验,可能与现实无关)

    不管引用了多少数据,比较两个内存地址都很快。但你必须先实习。如果代码中有

    var a = "1234";
    var b = "1234";
    
    然后引擎首先必须理解这两个字符串是相同的,并且可以指向相同的地址。因此,至少有一次,这些字符串必须进行充分比较。因此,基本上有以下几种选择:

    • 在解析代码时,引擎直接比较和插入字符串。在这种情况下,equals字符串应该获得相同的地址
    • 引擎可能会说“这些字符串是两个大字符串,我不想实习它们”,并且有两个副本
    • 发动机可能会在以后对这些管柱进行实习
    在后两种情况下,字符串比较将影响测试结果。在最后一种情况下,即使字符串最终被插入


    但正如我所写,一个狂野的理论,对于理论的圣人来说。首先,我希望看到一些JSPerf。

    基于字符串a和b的所有性能测试(参见原始帖子),操作
    a===b
    需要:

    • 恒定时间O(1)如果字符串被插入。从示例中可以看出,实习似乎只发生在直接指定的字符串中,如
      var str=“test”

    • 线性时间O(N)因为在所有其他情况下,首先比较两个字符串的长度。如果它是相等的,那么我们就可以进行逐个字符的比较。除此之外,它们当然是不平等的。N是字符串的长度


    我认为这是因为===运算符仅在比较对象时比较内存地址(类似于Java)。但是“某物”不是对象,它的类型是内置字符串。与比较数字相同,var a=2;var b=2;,如果你做a==b,你就不是在比较对象或内存地址。我知道你可以做var
    str=newstring(“test”)但我也不知道其中的含义。即使这样做,typeof str也将是“string”,而不是object。为了不破坏更多的浏览器,我已经删除了fiddle。我觉得它们太小了。重要提示:我刚刚测试了两个相等字符串的比较,其中包含5930496个字符,这些字符是使用var s1='…'构造的;变量s2='…';tooks 0ms,而char-tooks 20ms构造的相同字符串的比较。不知道,我不熟悉实习。字符串太长,文件大小为12MB。我将把它上传到Dropbox并用链接更新这个评论。谢谢。您能想出一个原因,为什么这是一个比将字符串作为两个对象处理更好的选择吗?有这样的开销吗?我看不出这是如何迫使引擎实际进行完整的字符串比较的。如果两个变量指向内存中某个地方保存的同一字符串,则它们将满足此要求。@michailidis Interning严格来说是一种实现,用于提高性能。