JavaScript的toString()和valueOf()区别到底是什么

很多人一直分不清到底是什么是tostring()和valueof(),更不知道他们之间有什么区别,下面我们就一起来探讨一下这两个函数。

从《JavaScript高级程序设计》这本书里面

var colors = ["red", "blue", "green"]; // 创建一个包含3 个字符串的数组  
alert(colors.toString()); // red,blue,green  
alert(colors.valueOf()); // red,blue,green  
alert(colors); // red,blue,green 

的这个例子,我们会有一个非常大的疑问
toString()和valueOf()区别到底是什么?

那么不如看下一个我写的例子

var arr = [1,2,3];  
alert(Array.isArray(arr.valueOf()));  
alert(Array.isArray(arr.toString()));  

猜猜结果是怎么样的?
结果是第一个是true而第二个是false

为什么呢,其实valueOf()调用完以后还是返回一个数组
这个数组被alert的时候会调用toString()函数
所以不是valueOf()和toString()函数相同,而是,根本就是间接的调用了toString()函数!

什么?你不信?
那好吧,我们来测试一下

var arr = [1,2,3];  
arr.toString = function () {  
    alert("你调用了toString函数");  
}  
alert(arr.valueOf());  

来来,猜猜结果。

结果就是我们会看到“你调用了toString函数”。

而对于数值,我们可以调用valueOf的时候直接可以获得数字进行计算,不必转化成字符串,所以不会调用toString
反言之,如果我们需要获得操作对象的字符串形式的时候就会调用其toString函数
举个例子
以下代码来自脚本之家的相关文章

var bbb = {  
 i: 10,  
 toString: function() {  
  console.log('toString');  
  return this.i;  
 },  
 valueOf: function() {  
  console.log('valueOf');  
  return this.i;  
 }  
}  
alert(bbb);// 10 toString  
alert(+bbb); // 10 valueOf  
alert(''+bbb); // 10 valueOf  
alert(String(bbb)); // 10 toString  
alert(Number(bbb)); // 10 valueOf  
alert(bbb == '10'); // true valueOf  
alert(bbb === '10'); // false  

他的文章讲的不是很清楚,为什么在我们重写了代码以后就会出现这样的情况

在这里我说一下我的理解
valueOf的意思是返回最适合该对象类型的原始值,而toString则是将在该对象类型的原始值以字符串形式返回。

第一个

alert(bbb);// 10 toString  

这里我们的alert函数需要是的字符串,所以获取的是字符串,而不是原始值,故而调用了toString
第二个

<span style="font-family: Arial, Helvetica, sans-serif;">alert(+bbb); // 10 valueOf</span>  

同理,alert要的是字符串不是原始值,其实是+bbb这个东西被调用了toString,而bbb被调用了valueOf
为了验证我们这样写

var a = {  
    i: 1,  
    valueOf: function () {  
        alert("你调用了a的valueOf函数");  
        return this.i;  
    },  
    toString: function () {  
        alert("你调用了a的toString函数");  
        return this.i;  
    }  
};  
var c = {  
    i: +a,  
    valueOf: function () {  
        alert("你调用了c的valueOf函数");  
        return this.i;  
    },  
    toString: function () {  
        alert("你调用了c的toString函数");  
        return this.i;  
    }  
};  
alert(c);  

其中让c=+a,那么即可知道结果,果然如此,调用了a的valueOf和c的toString

第三个

alert(''+bbb); // 10 valueOf  

同理,我们可以把上一段我写的程序里面的c:+a改成c:’’+a

第四个

alert(String(bbb)); // 10 toString  

String这个强制转换其实在其内部是调用了传入参数的toString函数……

第五个

alert(Number(bbb)); // 10 valueOf  

这个是有区别的,因为bbb的i属性是数值类型的,如果i为11111xxxxx这样的字符串,我们就可以看到调用了bbb的toString了
呐,代码例子

   var c = {  
    i: "11111xxxx",  
    valueOf: function () {  
        alert("你调用了c的valueOf函数");  
        return this.i;  
    },  
    toString: function () {  
        alert("你调用了c的toString函数");  
        return this.i;  
    }  
};  
alert(c);  

第六个

alert(bbb == '10'); // true valueOf  

这个里面的判等的顺序是,获取原始值,然后判断两边的原始值是否相等,所以调用valueOf

第七个也就是最后一个

alert(bbb === '10'); // false  

这个里面的判全等的第一个步骤是判断类型,因为类型都不一样了,所以后面什么都不会调用

讨论
另外,对于原文的这句话“ 在进行对象转换时(例如:alert(a)),将优先调用toString方法,如若没有重写toString将调用valueOf方法,如果两方法都不没有重写,但按Object的toString输出。”我不是很认同
原文例子

var aa = {   
 i: 10,   
 toString: function() {   
  console.log('toString');   
  return this.i;   
 }   
}   
alert(aa);// 10 toString   
alert(+aa); // 10 toString   
alert(''+aa); // 10 toString   
alert(String(aa)); // 10 toString   
alert(Number(aa)); // 10 toString   
alert(aa == '10'); // true toString   

我的观点有些不同,重写了的toString会被未重写的其prototype的valueOf隐式调用,而不是优先调用toString。虽然结果不同,但是其实没有优先级的变化。

var a = {  
        i: 1,  
        valueOf: function () {  
            alert("你调用了a的valueOf函数");  
            return Object.prototype.valueOf();  
        },  
        toString: function () {  
            alert("你调用了a的toString函数");  
            return this.i;  
        }  
    };  

    alert(+a);  
    alert(''+a);  

结果的确调用了a的toString和a的valueOf,而我们可以很轻易的从最初的原文例子看到,这两个alert是没有调用国toString的,那么我们即可证明重写了的toString会被未重写的其prototype的valueOf隐式调用。

另一个原文的例子

var bb = {   
 i: 10,   
 valueOf: function() {   
  console.log('valueOf');   
  return this.i;   
 }   
}  
alert(bb);// [object Object]   
alert(+bb); // 10 valueOf   
alert(''+bb); // 10 valueOf   
alert(String(bb)); // [object Object]   
alert(Number(bb)); // 10 valueOf   
alert(bb == '10'); // true valueOf   

而valueOf被重写以后,这个bb的对象没有toString,自然就会调用其prototype的toString,而那个toString的内容必然是

function toString() {  
    return '[object Object]';  
}  

,所以其实这个验证并没有什么意义。无论重写哪个函数最终的优先级都没变。

总结
所以那篇的结论并不是最根本的问题,最根本的问题是到底操作对象所处的环境是什么样的。
如果要求的是原始值那么就会调用valueOf,如果要求的是字符串那么就会调用toString。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值