简体   繁体   中英

Compare two strings with '<' and '>' operators in JavaScript

The comparison operators like > and < return Boolean value when their input is given as two string values.

I tried few examples:

 /* String vs String */ console.log('firstName' < 'lastname'); // true console.log('firstName' < 'Firstname'); // false console.log('!firstName' < 'lastname'); // true console.log('!firstName' < 'Firstname'); // true console.log('!firstName' < '!Firstname'); // false console.log('!firstName' < '_!Firstname'); // true console.log('@!firstName' < '_!Firstname'); // true console.log('@!firstName' < '2_!Firstname'); // false /* String vs Number */ console.log('@!firstName' < 2); // false console.log('@!firstName' < -1); // false /* String vs Special Numbers */ console.log('@!firstName' < Infinity); // false console.log('@!firstName' < -Infinity); // false console.log('@!firstName' < -Infinity + Infinity); // false /* String vs NaN */ console.log('@!firstName' < NaN); // false console.log(NaN.toString()); // "NaN" console.log('@!firstName' < "NaN"); // true /* String vs Arrays */ console.log('firstName' < [Infinity, -Infinity]); // false console.log('firstName' < ['Firstname', Infinity, -Infinity]); // false console.log('firstName' < ['2_Firstname', Infinity, -Infinity]); // false

I'm really curious to know how JavaScript really evaluates such expressions. In the above examples, I find this one as the most fascinating one console.log('@!firstName' < Infinity); // false console.log('@!firstName' < Infinity); // false .

So, the question I have is:

How is the comparison done using " is greater than " and " is less than " operators in JavaScript in these scenarios (from above examples):

  1. String vs String,
  2. String vs Number,
  3. String vs Special Numbers,
  4. String vs NaN,
  5. String vs Arrays

As said above, the formal specification is in the standard: http://www.ecma-international.org/ecma-262/7.0/#sec-abstract-relational-comparison , in layman's terms the logic is like this:

1) String vs String

Split both strings into 16-bit code units and compare them numerically. Note that code units != characters, eg "cafè" < "cafè" is true (really).

2) String vs other primitive

Convert both to numbers. If one of them is NaN , return false , otherwise compare numerically. +0 and -0 are considered equal, +/-Infinity is bigger/smaller than anything else.

3) String vs Object

Try to convert the object to a primitive, attempting, in order, [Symbol.toPrimitive]("number") , valueOf and toString . If we've got string, proceed to 1), otherwise proceed to 2). For arrays specifically, this will invoke toString which is the same as join .

String, String comparison is based on Unicode ordering (a is greater than A).

String, Number comparison first converts the string into a number before comparing (same with infinity).

String, Array comparison first converts the array into a string and then compares as above.

Javascript String Comparison
Javascript Object Comparison

The precise steps to take are described in the specification , which specifically describes what to do in the case that one (or both) sides of the comparison are NaN or +Infinity or -Infinity . For px < py , for example, the less-than operator calls the Abstract Relational Comparison Algorithm:

11.8.5 The Abstract Relational Comparison Algorithm

(If both items being compared are not strings, then:)

Let nx be the result of calling ToNumber(px). Because px and py are primitive values evaluation order is not important.

Let ny be the result of calling ToNumber(py).

If nx is NaN, return undefined.

If ny is NaN, return undefined.

If nx and ny are the same Number value, return false.

If nx is +0 and ny is −0, return false.

If nx is −0 and ny is +0, return false.

If nx is +∞, return false.

If ny is +∞, return true.

If ny is −∞, return false.

If nx is −∞, return true.

If the mathematical value of nx is less than the mathematical value of ny —note that these mathematical values are both finite and not both zero—return true. Otherwise, return false.

Else, both px and py are Strings

If py is a prefix of px, return false. (A String value p is a prefix of String value q if q can be the result of concatenating p and some other String r. Note that any String is a prefix of itself, because r may be the empty String.)

If px is a prefix of py, return true.

Let k be the smallest nonnegative integer such that the character at position k within px is different from the character at position k within py. (There must be such ak, for neither String is a prefix of the other.)

Let m be the integer that is the code unit value for the character at position k within px.

Let n be the integer that is the code unit value for the character at position k within py.

If m < n, return true. Otherwise, return false.

When both items being compared are strings, it effectively results in the code points of each character being compared. For example, 'firstName' < 'lastname' because the character code of f (102) is smaller than the character code of l (108). For '!firstName' < 'Firstname' , the character code of !(33) is smaller than the character code of F (70), so that evaluates to true as well. See the following snippet for an example of the implementation:

 function compare(left, right) { for (let i = 0; i < left.length; i++) { const c1 = left[i].charCodeAt(); const c2 = right[i].charCodeAt(); if (c1 !== c2) { console.log('Char code comparision:', c1 < c2, '< comparison:', left < right); break; } } } /* String vs String */ compare('firstName', 'lastname'); // true compare('firstName', 'Firstname'); // false compare('!firstName', 'lastname'); // true compare('!firstName', 'Firstname'); // true compare('!firstName', '!Firstname'); // false compare('!firstName', '_!Firstname'); // true compare('@!firstName', '_!Firstname'); // true compare('@!firstName', '2_!Firstname'); // false

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM