Is a function bigger than an array?

A friend of mine discovered some interesting behavior in some kind of Javascript code that I decided to continue.

Comparison

(function (x) {return x*x;}) > [1,2,3] 

returns true in most major browsers (Firefox, Chrome, Opera and Safari) and false in IE9. For me there is no logical result of this comparison, except for undefined , since there is no way to say that the function is larger than the array.

Considering this in the ECMA-script standard, he says that the actual arguments > when used for objects are the result of calling the internal ToNumber operation for the arguments. Some experiments and further reading tell me that this is not the same as applying type conversion, for example (Number) arg . Reading the specification, it’s hard for me to understand what is going on here.

Can someone fill me with what is really going on here?

+43
javascript function comparison arrays ecmascript-5
Feb 21 '12 at 16:34
source share
4 answers

Operands > not necessarily converted to numbers. the abstract relational comparison algorithm calls ToPrimitive with a Number hint, but ToPrimitive can still return a string (in the case of both functions and arrays).

So you end up comparing two lines. The result of calling toString in function objects is not specified by the specification, although most of the main engines return the source code of the function (or in some form, and the formatting changes). The result of calling toString on arrays is the same as join .

So the likelihood that you will end up doing this:

 "function (x) {return x*x;}" > "1,2,3" 

Since the exact shape of the string for a function can vary from browser to browser (and note Esailija research - it looks like IE9 preserves external () , Chrome doesn't work), it is not surprising that the result may vary.

+54
Feb 21 '12 at 16:37
source share

On IE <9, .toString ing (function (x) {return x*x;}) is given

 "(function (x) {return x*x;})" 

So far in chrome this gives:

 "function (x) {return x*x;}" 

If you compare:

 "function (x) {return x*x;}" > "1,2,3" // true "(function (x) {return x*x;})" > "1,2,3" // false 

This is actually the same as the comparison:

 "f" > "1" "(" > "1" 

Same as comparison:

 102 > 49 40 > 49 

So, how do we get from comparing functions and arrays with a simple mapping of numbers :)

+60
Feb 21 '12 at 16:45
source share

Let me dive into the ECMA specification. I have included section numbers so you can reference.

11.8.2 The operator is greater than the operator (>)

RelationalExpression Production: RelationalExpression> The Shift expression is evaluated as follows:

  • Let lref be the result of evaluating RelationalExpression.
  • Let lval be GetValue (lref).
  • Let rref be the result of evaluating the Shift expression.
  • Let rval be GetValue (rref).
  • Let r be the result of an abstract relational comparison rval <lval with LeftFirst set to false. (see 11.8.5).

An important part of this is abstract relational comparison. It is determined:

11.8.5 Abstract Relational Comparison Algorithm

The toPrimitive function toPrimitive first be called on objects. Although this is biased to return Numbers, if possible, strings can also be retrieved. As soon as this happens, the following will be considered:

but. If py is a px prefix, return false. (The string value of p is a prefix of the value of String q, if q can be the result of concatenating p and some other string r. Note that any String is a prefix in itself, since r can be an empty string.)

b. If px is the py prefix, return true.

from. Let k be the smallest non-negative integer such that the character at position k inside px differs from the character at position k inside py . (There must be a k, since neither String is a prefix of another.)

e. Let m be an integer that is the value of the code unit for the character at position k within px. e. Let n be an integer that is the value of the code unit for the character at position k inside py. e. If m <n, return true. Otherwise, return false.

This means that the first character in the string different from the other will be checked. As Esailija pointed out, the IE toString() function returns a slightly different line to a different line than other browsers, resulting in a different comparison.

This distinction between browsers seems valid, as indicated here:

15.2.4.4 Object.prototype.valueOf ()

When the valueOf method is called, the following steps are performed:

  • Let O be the result of calling ToObject, passing this value as an argument.
  • If O is the result of calling the Object constructor with the host object (15.2.2.1), then a. Return either O or another value, for example, the host object is initially passed to the constructor. The specific result that is returned is determined by the implementation.
  • Refund O.
+5
Feb 21 '12 at 17:37
source share

Both IE and other browsers will use the same string comparison for both objects. The reason for the difference is that IE converts the function to a string with letters:

 (function (x) {return x*x;}) 

Other browsers (testing in Firefox) will output their own compiled interpretation of the function:

 function (x) { return x * x; } 

Since the first character of the IE function representation ( which is higher than 1 , it will return false. Since f lower than 1 , other browsers will return true.

+2
Feb 21 2018-12-21T00:
source share



All Articles