javascript中的 ==

本文所有代码都在 node v0.10.28 中测试通过,因为node用的也是v8的javascript引擎,所以理论上来说在chrome中的表现应该一致,其它引擎各位可以自己测试

准备工作

我们先定义一个对象来进行比较

?

1
2
3
function foo() {
   this .name = "foo" ;
}

再定义一个函数来比对

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function compare(f) {
   console.log( "\ncompare with number:" );
   console.log( "number f == 1: %s" , f == 1 );
   console.log( "number f == 0: %s" , f == 0 );
 
   console.log( "\ncompare with string:" );
   console.log( "string f == \"\" : %s" , f == "" );
   console.log( "string f == \"foo\" : %s" , f == "foo" );
 
   console.log( "\ncompare with boolean:" );
   console.log( "boolean f == true : %s" , f == true );
   console.log( "boolean f == false : %s" , f == false );
 
   console.log( "\ncompare with object:" );
   console.log( "object f == {} : %s" , f == {});
}

第一次比较

?

1
compare( new foo());

输出结果:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
compare with number:
number f == 1 : false
number f == 0 : false
 
compare with string:
string f == "" : false
string f == "foo" : false
 
compare with boolean :
boolean f == true : false
boolean f == false : false
 
compare with object:
object f == {} : false

这个结果大家基本上都能理解

第二次比较

这次我们给这个对象添加一个方法 valueOf 然后再来进行比较看看

?

1
2
3
foo.prototype.valueOf  = function() {
     return 0 ;
};

?

1
compare( new foo());

结果为:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
compare with number:
number f == 1 : false
number f == 0 : true
 
compare with string:
string f == "" : true
string f == "foo" : false
 
compare with boolean :
boolean f == true : false
boolean f == false : true
 
compare with object:
object f == {} : false

这个结果我们发现

  • 和 0 比较

  • 和空字符串比较

  • 和false比较

这三种情况返回 true

这个结果让人不好理解
我们在valueOf方法中加入一些输出再来看看

?

1
2
3
4
foo.prototype.valueOf  = function() {
   console.log( 'valueOf: ' + this .name);
   return 0 ;
};

?

1
compare( new foo());

输出结果为:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
compare with number:
valueOf: foo
number f == 1 : false
valueOf: foo
number f == 0 : true
 
compare with string:
valueOf: foo
string f == "" : true
valueOf: foo
string f == "foo" : false
 
compare with boolean :
valueOf: foo
boolean f == true : false
valueOf: foo
boolean f == false : true
 
compare with object:
object f == {} : false

现在我们可以猜测一下了, javascript在进行对象和基本数据类型(暂且把string也当做一种基本数据类型,下面说基本数据类型的时候也会带上string)比较的时候,会调用对象的valueOf方法的返回值来进行比较.

这样就可以解释number比较中为什么和0比较是true了,
但是还有和空字符串比较是true,和false比较是true,这里我的理解是 javascript在数字和字符串以及boolean进行比较的时候,会转换成数字后进行比较,所以 0 == ""0 == false也是true

只有最后一个和对象比较的时候没有打印 valueOf: foo 所以也可以认为是对象比较时,只比较引用地址,理论上来说,对象比较 == 和 === 应该是一样的,例如如下代码:

?

1
2
3
4
5
var b1 = new Boolean( false );
var b2 = new Boolean( false );
 
console.log(b1 == b2);
console.log(b1 === b2);

输出两次false

第三次比较

这次我们将valueOf方法再修改一下,返回不是基本数据类型试一下,就返回自己吧

?

1
2
3
4
foo.prototype.valueOf  = function() {
     console.log( 'valueOf: ' + this .name);
     return this ;
};

?

1
compare( new foo());

输出结果为:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
compare with number:
valueOf: foo
number f == 1 : false
valueOf: foo
number f == 0 : false
 
compare with string:
valueOf: foo
string f == "" : false
valueOf: foo
string f == "foo" : false
 
compare with boolean :
valueOf: foo
boolean f == true : false
valueOf: foo
boolean f == false : false
 
compare with object:
object f == {} : false

这次和第一次比较没什么出入,只是打印了一些方法调用日志而已,结果也理所当然的应该这样了.

但是javascript为什么没有递归调用我们的valueOf方法呢,按道理我们返回了自己,然后它进行比较的时候应该再次调用valueOf

这次我们再加入一个toString方法来看看

?

1
2
3
4
foo.prototype.toString = function(){
     console.log( this .name + " : toString" );
     return this .name;
}

?

1
compare( new foo());

输出结果为:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
compare with number:
valueOf: foo
foo : toString
number f == 1 : false
valueOf: foo
foo : toString
number f == 0 : false
 
compare with string:
valueOf: foo
foo : toString
string f == "" : false
valueOf: foo
foo : toString
string f == "foo" : true
 
compare with boolean :
valueOf: foo
foo : toString
boolean f == true : false
valueOf: foo
foo : toString
boolean f == false : false
 
compare with object:
object f == {} : false

我们发现每次输出valueOf的后面都跟随了一个toString的调用.

也就是说 javascript在调用valueOf后发现不是基本数据类型的时候,会调用toString的返回值再来进行比较
和我们观测到的结果一致,只有 f== "foo" 的结果是true

这样也可以解释为什么没有递归调用我们的valueOf方法了

接下来我们再狠一点,toString我们也返回自己,看看javascript会怎么处理

第四次比较

修改toString方法为:

?

1
2
3
4
foo.prototype.toString = function(){
     console.log( this .name + " : toString" );
     return this ;
}

?

1
compare( new foo());

这次的结果会在意料之外的:

结果为:

?

1
2
3
4
5
6
7
8
9
10
11
12
console.log( "number f == 1: %s" , f == 1 );
                                      ^
TypeError: Cannot convert object to primitive value
     at compare (/home/ 0x0001 /Desktop/test.js: 25 : 38 )
     at Object.<anonymous> (/home/ 0x0001 /Desktop/test.js: 41 : 1 )
     at Module._compile (module.js: 456 : 26 )
     at Object.Module._extensions..js (module.js: 474 : 10 )
     at Module.load (module.js: 356 : 32 )
     at Function.Module._load (module.js: 312 : 12 )
     at Function.Module.runMain (module.js: 497 : 10 )
     at startup (node.js: 119 : 16 )
     at node.js: 906 : 3

结果报异常了

最后我觉得,javascript在将对象和基本数据类型进行比较的时候,会先调用valueOf的返回值来进行比较,如果valueOf返回的不是基本数据类型,那么继续调用toString方法的返回值来进行比较,
如果toString的返回值还不是基本数据类型,那么就无法比较了


你可能感兴趣的:(javascript中的 ==)