JavaScript中比较两个字符串时,为什么一个字符串会被认为比另一个字符串大?

68

我从一本书中看到了这段代码:

var a = "one";
var b = "four";
a>b; // will return true

但它没有提到为什么"one"比"four"大。我尝试了c = "a",它比a和b都小。我想知道JavaScript如何比较这些字符串。


2
"one" > "a" 是成立的,因为 "o" > "a"。你明白为什么 "o" > "a" 吗? - Matt Ball
3
不,我正在尝试搜索一些东西。你能给我一些提示吗? - patriot7
6
字母表中的字母顺序越靠后,其对应的值就越大。以下几个比较成立:"z" > "y"; "y" > "c"; "c" > "b"; "b" > "a"; - Luke
1
只是一个旁注,因为字符串化的数字(“1”“2”“3”)的工作方式相同,它会导致错误的排序,因为“5”大于“10”。因此,在尝试对数字进行排序时,请验证它们是真正的数字而不是字符串。 - Harps
1
@Harps:你是在暗示“自然排序”吗,比如JavaScript中字母数字字符串的自然排序,它可以“正确地”将字符串“version10”排在字符串“version5”之后? - David Cary
显示剩余2条评论
5个回答

60
因为,和许多编程语言一样,字符串是按字典顺序比较的。
你可以将其视为字母排序的高级版本,不同之处在于字母排序仅涵盖26个字符az

这个答案是针对一个问题的回答,但逻辑完全相同。另一个好的例子:String Compare "Logic"


4
如果有疑惑,查找规范。在这种情况下,请参阅ECMAScript规范的第11.8.5节。当然,为了更容易解析的答案,SO存档也很有用。 :-) - mmigdol
5
解释“字符的值”最好的方法是指向一个ASCII表,该表表示每个字符的十进制值。 - ps2goat
@ps2goat 很好的观点。随意建议编辑此答案以添加 :) - Matt Ball

14

"one"以'o'开头,"four"以'f'开头,'o'在字母表中比'f'靠后,因此"one"大于"four"。请参考此页面获取一些JavaScript字符串比较的示例(包含解释!)。


3

Javascript中的>运算符使用词典顺序。'f'在'o'之前,因此比较"one" > "four"返回true


2
ECMAScript语言规范的第11版中,"抽象关系比较"条款定义了如何计算x < y。当表达式被反转时(即x > y),我们应该计算y < x的结果。

因此,要解决"one" > "four",我们必须解决"four" < "one"

同样的条款也说:

字符串的比较使用代码单元值序列上的简单词典排序。

如果两个操作数都是字符串,则会出现这种情况:

  • 如果Type(px)是字符串并且Type(py)也是字符串,则
    • 如果IsStringPrefix(py, px)为真,则返回false。
    • 如果IsStringPrefix(px, py)为真,则返回true。
    • 令k为最小的非负整数,使得px中索引k处的代码单元与py中索引k处的代码单元不同。 (对于任何一个字符串都不是另一个字符串的前缀,因此必须存在这样的k。)
    • 令m为px中索引k处的代码单元的数值。
    • 令n为py中索引k处的代码单元的数值。
    • 如果m < n,则返回true。否则返回false。
  • (对于本示例我们可以安全忽略前两条)

    那么让我们看一下“four”的代码单元:

    [..."four"].map(c => c.charCodeAt(0));
    //=> [102, 111, 117, 114]
    

    而对于“one”:

    [..."one"].map(c => c.charCodeAt(0));
    //=> [111, 110, 101]
    

    所以现在我们必须找到一个值为k(从0开始)的变量,使得m[k]n[k]不同:

    |   | 0   | 1   | 2   | 3   |
    |---|-----|-----|-----|-----|
    | m | 102 | 111 | 117 | 114 |
    | n | 111 | 110 | 101 |     |
    

    我们可以看到,在0处,m [0]n [0]是不同的。
    由于m [0] 为真,则"four" < "one"为真,因此"one" > "four"为真。

    "☂︎" < "☀︎"的返回值是什么?

    [..."☂︎"].map(c => c.charCodeAt(0))
    //=> [9730, 65038]
    [..."☀︎"].map(c => c.charCodeAt(0))
    //=> [9728, 65038]
    

    |   | 0    | 1     |
    |---|------|-------|
    | m | 9730 | 65038 |
    | n | 9728 | 65038 |
    

    由于 9730 < 9728 是假的,那么 "☂︎" < "☀︎" 也是假的,这很好,因为雨并不比阳光更好(显然 ;)。


    2
    当你在JavaScript中使用像<=这样的关系运算符比较字符串时,你正在比较它们的基本Unicode代码单元,从开头逐个比较,第一次找到任何差异时停止。 "one" > "four"是true,因为"o"(代码单元111)大于"f"(代码单元102)。由于在第一个字符中找到了差异,其余字符被忽略。 如果你有"fb" > "fa",那么两个"f"将被比较,发现它们相同,然后将比较每个字符串的下一个字母("b""a")。如果字符串长度不同并且更长的字符串以较短的字符串开头,则较短的字符串“小于”较长的字符串("aaa" < "aaab"true)。

    这个操作以前在规范中由抽象关系比较操作处理,但现在使用小于操作。


    事实上,关系运算符使用的是代码单元,这是不适用于字符串的一个很好的理由,因为在许多情况下,代码单元的顺序与人们根据其语言的期望不匹配("é" < "z"false,这对法语说话者可能没有什么意义);相反,应该使用 localeCompare,或许还可以使用一些可选设置,以便为字符串包含的语言适当地进行比较("é".localeCompare("z", "fr") < 0true,因为在“fr”区域设置中,é在适当的词典顺序中排在z之前)。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接