JavaScript 对象转换,toString,valueOf

开始这个话题之前,我们先看一下下面的几个例子:

parseInt(0.0000004)  // 4
![]==[] //true
['x','y'] == 'x,y' //true
alert({name:'mofei'})  //"[object Object]"

结果有时候会让我大吃一惊,这是为什么呢?今天就和大家讨论一下JavaScript的对象转换。

基础类型

先让我们了解一下JavasScript转换的“原始类型(primitive value)”:

Number

String

Boolean

在JavaScript进行对比或者各种运算的时候会把对象转换成这些类型,从而进行后续的操作,下面逐一说明:

String转换

在某个操作或者运算需要字符串的时候,往往会触发Object的String转换,举个例子

var obj={name:'Mofei'}
var str = ' ' + obj
console.log(str);  //   [object Object]

上述的例子中,在字符串相加的过程中,系统调用了obj的String转换,具体规则如下:

  1. 如果toString方法存在并且返回“原始类型”,返回toString的结果。
  2. 如果toString方法不存在或者返回的不是“原始类型”,调用valueOf方法,如果valueOf方法存在,并且返回“原始类型”数据,返回valueOf的结果。
  3. 其他情况,抛出错误。

我们可以用下面的方法简单的证明上面的规则:

首先我们尝试改写一个对象的toString方法

var a={
    toString:function(){
        console.log('调用了 a.toString');
        return '111';
    }
}
alert(a);

//调用了 a.toString
// 111

可以看到,系统在执行 ' '+a 的时候,自动调用了a的toString方法,将a(Object)转换成了String。

下面我们尝试证明如果toString()方法不可用的时候系统会调用valueOf()方法

var a={
    toString:function(){
        console.log('调用了 a.toString');
        return '111';
    },
    valueOf:function(){
        console.log('调用了 a.valueOf');
        return '111';
    }
}
alert(a);

//调用了 a.toString

这里我们增加了valueOf方法,但是发现系统并没有调用,这是因为,第一步toString返回的是原始类型,我们尝试把第一步返回的值改成一个对象 {}

var a={
    toString:function(){
        console.log('调用了 a.toString');
        return {};
    },
    valueOf:function(){
        console.log('调用了 a.valueOf');
        return '111';
    }
}
alert(a);

// 调用了 a.toString
// 调用了 a.valueOf

从结果可以看到,当toString不可用的时候,系统会再尝试valueOf方法,我们继续修改valueOf方法,把valueOf方法也改成返回对象 {}

var a={
    toString:function(){
        console.log('调用了 a.toString');
        return {};
    },
    valueOf:function(){
        console.log('调用了 a.valueOf');
        return {};
    }
}
alert(a);

// 调用了 a.toString
// 调用了 a.valueOf
//  Uncaught TypeError: Cannot convert object to primitive value

可以发现,如果toString和valueOf方法均不可用的情况下,系统会直接返回一个错误。

Number转换

下面说说Number转换,同理,当需要使用Number时,( 如Math.sin() )等,解释器会尝试将对象转换成Number对象。

通常有如下的情况会触发Number转换

  1. 方法参数需要Number的时候,如Math.sin(obj)等
  2. 对比的时候,如 obj == 'abc'
  3. 运算的时候,如 obj + 123

转换规则如下:

  1. 如果valueOf存在,且返回“原始类型”数据,返回valueOf的结果。
  2. 如果toString存在,且返回“原始类型”数据,返回toString的结果。
  3. 报错。

可以参考String转换的方法进行验证,这里只列出一种典型的方法,其他的可以自己动手来修改

var a={
    toString:function(){
        console.log('调用了 a.toString');
        return 12;
    },
    valueOf:function(){
        console.log('调用了 a.valueOf');
        return {};
    }
}
a+1
//调用了 a.valueOf
//调用了 a.toString
//13

可以看到,这里我们改写了valueOf和toString方法,系统在调用valueOf方法之后发现返回的不是“原始类型”数据,于是又尝试调用了toString方法,并返回了该方法返回的值12,最后+1变成了13。

Boolean转换

在进行布尔比较的时候,比如 if(obj) , while(obj)等等,会进行布尔转换,布尔转换遵循如下规则:

布尔值
true/false true/false
undefined,null false
Number 0,NaN 对应 false, 其他的对应 true
String ""对应false,其他对应true('0'对应的是true)
Object true

举个比较典型的例子

[] == ![]  //true

// 首先第一步右边的是逻辑判断![],说以先转成boolean
// [] == !true
// [] == false
// 左边不是原始类型,尝试把左边转成原始类型,变成
// '' == false
// 转成Number
// 0 == 0

总结

通过上述的介绍,一开始提到的问题应该都很容易得到答案了。

parseInt(0.0000004)  // 4
![]==[] //true
['x','y'] == 'x,y' //true
alert({name:'mofei'})  //"[object Object]"

关于这些转换,有时确实很让人费解,不过在了解原理之后,就会变得很容易了。有什么问题,可以给我留言,我会第一时间回复。

Write a response...
Mofei Zhu
publish
Mofei
2017-10-25 10:32
@RayJune  [可爱]
0
 Replay
@Mofei  
Replay
RayJune
2017-10-25 10:21
非常有帮助,感谢博主
1
 Replay
@RayJune  
Replay
匿名
2015-12-17 17:52
var a = {a:1111}; Object.prototype.toString = function(){ console.log('toString ~~~~~~~~') } Object.prototype.valueOf = function(){ console.log('valueOf ~~~~~~~~') } console.log(a+'') // valueOf ~~~~~~~~
0
 Replay
@  
Replay
剧中人
2015-05-17 13:54
@Mofei 为何是“苍”盛!
0
 Replay
@剧中人  
Replay
Mofei
2015-05-17 12:46
@剧中人 感谢您为互联网事业的繁荣苍盛做出的贡献。
0
 Replay
@Mofei  
Replay
剧中人
2015-05-17 11:11
@Mofei 为毛找我做测试,我是可爱的小白鼠么!
0
 Replay
@剧中人  
Replay
Mofei
2015-05-15 22:08
@剧中人 测试新版回复
0
 Replay
@Mofei  
Replay
匿名
2015-04-20 20:29
@剧中人 因为({name:'mofei'}).toString()和({name:'lay'}).toString()的结果都是 "[object Object]"
0
 Replay
@  
Replay
剧中人
2015-04-20 20:25
为什么alert({name:'mofei'})和alert({name:'lay'})弹出值是一样的捏?十分不解!
0
 Replay
@剧中人  
Replay