论坛首页 Web前端技术论坛

indexOf 与比较操作

浏览 5759 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (7)
作者 正文
   发表时间:2009-04-17   最后修改:2010-08-30

 

  现在我已经大量在平时应用中应用Extjs core,问题也时常发生,如  Ext.DomHelper 添加 option 问题  ,

 

  今天又遇到了一个Ext使用中很重要但容易忽略问题 ,与大家共享:  如下面代码:

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>indexOf 测试</title>
<script type="text/javascript" src="ext-base.js"></script>
<script type="text/javascript" src="ext-core.js"></script>


<script type="text/javascript">
	
	Ext.onReady(function() {
		
		/*
    Array.prototype['indexOf']= function(o){
       for (var i = 0, len = this.length; i < len; i++){
 	      if(this[i] == o) return i;
       }
 	   return -1;
    };
    */
		var x=[5001, 5003, 5004];
		var y='5001';
		
		var z=x.indexOf(y);
		
		alert(z);
});


</script>
</head>
<body>

</body>
</html>

 

根据 Extjs API 文档 ,

 

 

indexOf ( Object o  ) : Number

Checks whether or not the specified object exists in the array.
Checks whether or not the specified object exists in the array.
Parameters:
  • o : Object
    The object to check for
Returns:
  • Number
    The index of o in the array (or -1 if it is not found)

先不管 是否他是 完全相等 (===) 或 相容相等(==) ,至少我们期望在各个浏览器上表现一致,但是很不幸,据我测试

ie 系列 : alert 0
firefox 系列 : alert -1


那么查看 Extjs 的源代码:(注意:  代码存在 ext-2.2.1/adapter/ext-base.js   与 source/core/Ext.js  并不存在于 source/adapter/ext-base.js

Ext.applyIf(Array.prototype, {
    
    indexOf : function(o){
       for (var i = 0, len = this.length; i < len; i++){
 	      if(this[i] == o) return i;
       }
 	   return -1;
    },
 

可见 Ext 采用的是相容相等,但是又采用了 Ext.applyIf,那么可以分析到 firefox 并没有得到这个方法:

 

firefox从1.5 就实现了JavaScript 1.6  (非 ecmascript 标准),而 Array 的 indexOf 方法正是从1.6成为原生方法

 

而 ie (直至最新的ie8) 实现 ecmascript 标准 262 即 javascrip 1.5,Array 并无 indexOf方法,于是由extjs 设置。

 

http://en.wikipedia.org/wiki/JavaScript

 

 

而 javascrip 1.6 中明确规定是对象在数组中出现的索引,即采用的是严格相等,而 ie 执行extjs 设置的相容相等,这也正解释了为什么 ie ff 会在这个问题上表现不一致。

 

https://developer.mozilla.org/En/Core_javascript_1.5_reference:objects:array:indexof

 

 

我认为 Extjs 需对此负一定责任, John Resig 曾说过库是用来屏蔽各个浏览器差异的 ,而 这个问题正是体现了两个浏览器的迥然不同。

 

John Resig
Advancing JavaScript with Libraries(1)


http://video.yahoo.com/watch/410472/2391234

 

Advancing JavaScript with Libraries(2)


http://video.yahoo.com/watch/412541/2395771

 

 

 

对于 Extjs 使用的相容相等,觉得也不是很好,对于这方面应该尽量使用严格相等 === ,在 Douglas Crockford 的
The JavaScript Programming Language 讲座中也提到过。

 

Douglas Crockford
The JavaScript Programming Language(1)


http://video.yahoo.com/watch/111593/1710507

 

The JavaScript Programming Language(2)


http://video.yahoo.com/watch/111594/1710553

 

The JavaScript Programming Language(3)


http://video.yahoo.com/watch/111595/1710607

 

The JavaScript Programming Language(4)


http://video.yahoo.com/watch/111596/1710658

 

 

总之很简单的解决:这个改成 ===  就可以了,不过不知道为什么这个问题在Ext3.0 beta 中仍然没有改变.

 

 

 

附录 : == 使用注意

 

 

参见 ecma262


The comparison x == y, where x and y are values, produces true or false. Such a comparison is performed as follows:
1.    If Type(x) is different from Type(y), go to step 14.
2.    If Type(x) is Undefined, return true.
3.    If Type(x) is Null, return true.
4.    If Type(x) is not Number, go to step 11.
5.    If x is NaN, return false.
6.    If y is NaN, return false.
7.    If x is the same number value as y, return true.
8. Ifxis+0andyis−0,returntrue.
9. Ifxis−0andyis+0,returntrue.
10. Return false.
11.If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same
length and same characters in corresponding positions). Otherwise, return false.
12. If Type(x) is Boolean, return true if x and y are both true or both false. Otherwise, return false.
13.Return true if x and y refer to the same object or if they refer to objects joined to each other (see 13.1.2). Otherwise, return false.
14. If x is null and y is undefined, return true.
15. If x is undefined and y is null, return true.
16.If Type(x) is Number and Type(y) is String, return the result of the comparison x == ToNumber(y).
17.If Type(x) is String and Type(y) is Number, return the result of the comparison ToNumber(x) == y.
18. If Type(x) is Boolean, return the result of the comparison ToNumber(x) == y.
19. If Type(y) is Boolean, return the result of the comparison x == ToNumber(y).
20.If Type(x) is either String or Number and Type(y) is Object,return the result of the comparison x == ToPrimitive(y).
21.If Type(x) is Object and Type(y) is either String or Number,return the result of the comparison ToPrimitive(x) == y.
22. Return false.


ToPrimitive :
1.    Call the [[Get]] method of object O with argument "valueOf".
2.    If Result(1) is not an object, go to step 5.
3.    Call the [[Call]] method of Result(1), with O as the this value and an empty argument list.
4.    If Result(3) is a primitive value, return Result(3).
5.    Call the [[Get]] method of object O with argument "toString".
6.    If Result(5) is not an object, go to step 9.
7.    Call the [[Call]] method of Result(5), with O as the this value and an empty argument list.
8.    If Result(7) is a primitive value, return Result(7).
9.    Throw a TypeError exception.


所以 == 可能会抛出异常的:

 

var b={
    toString :function(){
return {};    
},

valueOf : function(){
    return {};
}
};

try{
alert(b == 'a');
}
catch(e){alert(e);}

 

再试试这个:

 

"true" == true

 

通俗的解释可参见玉伯的总结:例子 以及解释

 

ps:ecma262-5rd 的一些备注

1.一些省心的诀窍,免得读代码的其他人不熟悉转换规则
String comparison can be forced by: "" + a == "" + b.

Numeric comparison can be forced by: +a == +b.

Boolean comparison can be forced by: !a == !b.

2.注意 == 不具有传递性:

var a=new String("xx");var b= "xx" ;var c=new String("xx");
a==b ,b==c but a!=c

 

   发表时间:2009-04-18  
var y='5001'是字符串,怎么能和整数数组比较?
改成var y=5001
0 请登录后投票
   发表时间:2009-04-18   最后修改:2009-04-18
这不算是bug,把y改成整数后,ie也通过了。如果按照你要求的,倒是bug了。
0 请登录后投票
   发表时间:2009-04-18  
netharry 写道

var y='5001'是字符串,怎么能和整数数组比较?改成var y=5001


照你那么说的话  == 和 === 有在语言规范中同时存在的必要么?这是 javascript 不是 java ,javascript 弱类型 这种比较很常见 ,内存里你存的是 number 数组,从 input 取来的都是 string ,这两者比较很常见


0 请登录后投票
   发表时间:2009-04-18  
netharry 写道

这不算是bug,把y改成整数后,ie也通过了。如果按照你要求的,倒是bug了。

我现在讨论的是 indexOf 这个在 ff ie浏览器表现一致性问题 , 不管 indexOf 的输入是什么
0 请登录后投票
   发表时间:2009-04-18  
我对js了解并不多,但我知道:
add=function(a,b){
  return a+b;
}
alert(add(1,4))和alert(add('1','4'))并不是一回事。而且有个toString(),我想不会是个摆设。
0 请登录后投票
   发表时间:2009-04-20   最后修改:2009-04-20
这个勉强算是个bug,就好像我们利用算符优先法则可以少写很多的括号,但是一般正常的程序员编程序的时候都不会这么做。
不同编译器和解释器定义的优先规则也是不一样的。
0 请登录后投票
   发表时间:2009-06-13  
这个不是Bug哦,FireFox实现了原生Array的indexOf()方法(其它浏览器IE、Opera、Safari都没有原生实现),在扩展的时候用的是Ext.applyIf(...),也就是说,如果有原生实现就不拿Ext自己的实现去覆盖。我当初也纳闷来着。。。
0 请登录后投票
   发表时间:2009-06-13  
damoqiongqiu 写道

这个不是Bug哦,FireFox实现了原生Array的indexOf()方法(其它浏览器IE、Opera、Safari都没有原生实现),在扩展的时候用的是Ext.applyIf(...),也就是说,如果有原生实现就不拿Ext自己的实现去覆盖。我当初也纳闷来着。。。


你看清楚我写的东西了么?....
0 请登录后投票
   发表时间:2009-06-15  
LZ并不是说EXT实现的indexOf有BUG,而是说本身的实和原生的实现不一致,进而造成同样的库在不同浏览器里表现不一致而产生使用陷井,这才是BUG
0 请登录后投票
论坛首页 Web前端技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics