一个函数比一个数组大?

我的一个朋友在一些Javascript代码中发现了一些有趣的行为,我决定进一步调查。

比较

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

在大多数主stream浏览器(Firefox,Chrome,Opera和Safari)中返回true ,在IE9中返回false 。 对我来说,这个比较没有任何逻辑结果,因为没有办法说函数大于数组。

在ECMA脚本标准中读到这一点,它说在对象上使用时的实际参数是对参数调用ToNumber内部操作的结果。 一些实验和进一步的阅读告诉我,这与应用(Number) arg类的types转换不同。 阅读规范,我很难弄清楚这里发生了什么。

任何人都可以填写我在这里发生了什么?

操作数>不一定转换为数字。 抽象关系比较algorithm使用提示 Number调用ToPrimitive ,但ToPrimitive仍然可以返回一个string(在函数和数组的情况下)。

所以你最终比较两个string。 对函数对象调用toString的结果并不是由spec定义的,尽pipe大多数主要的引擎都返回了函数的源代码(或者某种forms的,格式不同)。 在数组上调用toString的结果与join相同。

所以可能性基本上是这样的:

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

由于函数string的确切forms可能因浏览器到浏览器而异(并注意Esailija的调查 – 看起来像IE9保持外() ,铬没有),结果可能会有所不同。

在IE <9中.toString ing (function (x) {return x*x;})给出

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

而在铬它给:

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

如果你比较:

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

这与比较实际上是一样的:

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

这与比较相同:

 102 > 49 40 > 49 

所以这就是我们如何从一个函数和数组比较到一个简单的数字比较:)

让我们来深入ECMA规范。 我已经包含了部分编号,以便您参考。

11.8.2大于运算符(>)

生产RelationalExpression:RelationalExpression> ShiftExpression的计算方法如下:

  1. 让lref是评估RelationalExpression的结果。
  2. 让lval成为GetValue(lref)。
  3. 让rref是评估ShiftExpression的结果。
  4. 让rval是GetValue(rref)。
  5. 设r是执行抽象关系比较的结果,rval <lval,LeftFirst等于false。 (见11.8.5)。

其中重要的部分是抽象关系比较 。 其中定义:

11.8.5抽象关系比较algorithm

toPrimitive函数将首先在对象上被调用。 虽然这是有偏见的返回数字,如果可以的话,string也可以派生。 一旦发生这种情况,将检查以下内容:

一个。 如果py是px的前缀,则返回false。 (string值p是string值q的前缀,如果q可以是连接p和其他stringr的结果,请注意任何string都是它自己的前缀,因为r可能是空string。

湾 如果px是py的前缀,则返回true。

C。 令k是最小的非负整数,使得px内位置k上的字符与py内位置k上的字符不同 。 (必须有这样的一个string,因为这两个string都不是另一个的前缀。)

d。 设m为px内位置k处字符的代码单元值的整数。 即 设n是py中位置k上的字符的代码单元值的整数。 F。 如果m <n,则返回true。 否则,返回false。

这意味着将检查string中与第一个字符不同的第一个字符。 正如Esailija指出的那样,IE的toString()函数返回的string与其他浏览器略有不同,导致了不同的比较。

浏览器之间的这种差异似乎是有效的,如下所述:

15.2.4.4 Object.prototype.valueOf()

当调用valueOf方法时,将采取以下步骤:

  1. 设O是调用ToObject传递该值作为参数的结果。
  2. 如果O是使用主机对象(15.2.2.1)调用Object构造函数的结果,那么a。 返回O或其他值,例如最初传递给构造函数的主机对象。 返回的具体结果是实现定义的。
  3. 返回O.

IE和其他浏览器都将使用相同的string比较这两个对象。 不同的原因是IE会将函数转换为input的文字string:

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

其他浏览器(在Firefox上testing)将输出它自己编译的函数解释:

 function (x) { return x * x; } 

由于IE函数表示的第一个字符是(大于1 ,所以返回false,由于f低于1 ,所以其他浏览器会返回true。