一个函数大于一个数组?

时间:2012-02-21 16:34:13

标签: javascript arrays function comparison ecmascript-5

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

比较

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

在大多数主要浏览器(Firefox,Chrome,Opera和Safari)中返回true,在IE9中返回false。对我来说,除了undefined之外,没有其他比较的逻辑结果,因为没有办法说函数大于数组。

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

任何人都可以告诉我这里真正发生的事情吗?

4 个答案:

答案 0 :(得分:60)

在IE< 9中,.toString (function (x) {return x*x;})提供了

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

在chrome中,它给出了:

"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

这就是我们从函数和数组比较到简单数字比较的方式:)

答案 1 :(得分:54)

>的操作数不一定转换为数字。 abstract relational comparison algorithm使用提示 ToPrimitive调用Number,但ToPrimitive仍可能返回一个字符串(在函数和数组的情况下,它确实)。

所以你最终比较了两个字符串。调用toString on function objects的结果不是由规范定义的,尽管大多数主要引擎返回函数的源代码(或其某种形式,并且格式不同)。调用toString on arrays的结果与join相同。

所以你很可能最终会这样做:

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

由于该功能的字符串的确切形式可能因浏览器而异(并注意Esailija's investigations - 看起来IE9保持外部(),Chrome不会),它不是太令人惊讶,结果可能会有所不同。

答案 2 :(得分:5)

让我们深入了解ECMA规范。我已经包含了部分编号,因此您可以参考。

11.8.2大于运算符(>)

  

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

     
      
  1. 让lref成为评估RelationalExpression的结果。
  2.   
  3. 让lval成为GetValue(lref)。
  4.   
  5. 让rref成为评估ShiftExpression的结果。
  6.   
  7. 让rval为GetValue(rref)。
  8.   
  9. 设r为执行抽象关系比较 rval<左边的Lval等于false。 (看到   11.8.5)。
  10.   

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

11.8.5抽象关系比较算法

首先在对象上调用toPrimitive函数。虽然如果可以的话,这会偏向于返回Numbers,但也可以派生字符串。一旦发生这种情况,将检查以下内容:

  

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

     

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

     

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

     

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

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

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

15.2.4.4 Object.prototype.valueOf()

  

调用valueOf方法时,将执行以下步骤:

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

答案 3 :(得分:2)

IE和其他浏览器都将对两个对象使用相同的字符串比较。产生差异的原因是IE会将函数转换为输入的文字字符串:

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

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

function (x) {
    return x * x;
}

由于IE的函数表示的第一个字符是(,它高于1,它将返回false。由于f低于1,因此其他浏览器将返回true。