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

javascript 同时被 2 个专栏收录
74 篇文章 1 订阅
17 篇文章 0 订阅

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

[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. var colors = ["red""blue""green"]; // 创建一个包含3 个字符串的数组  
  2. alert(colors.toString()); // red,blue,green  
  3. alert(colors.valueOf()); // red,blue,green  
  4. alert(colors); // red,blue,green  

的这个例子,我们会有一个非常大的疑问

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


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

[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. var arr = [1,2,3];  
  2. alert(Array.isArray(arr.valueOf()));  
  3. alert(Array.isArray(arr.toString()));  


猜猜结果是怎么样的?

结果是第一个是true而第二个是false


为什么呢,其实valueOf()调用完以后还是返回一个数组

这个数组被alert的时候会调用toString()函数

所以不是valueOf()和toString()函数相同,而是,根本就是间接的调用了toString()函数!


什么?你不信?

那好吧,我们来测试一下


[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. var arr = [1,2,3];  
  2. arr.toString = function () {  
  3.     alert("你调用了toString函数");  
  4. }  
  5. alert(arr.valueOf());  

(坑爹阿csdn,朕的代码缩进)

来来,猜猜结果。


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


而对于数值,我们可以调用valueOf的时候直接可以获得数字进行计算,不必转化成字符串,所以不会调用toString

反言之,如果我们需要获得操作对象的字符串形式的时候就会调用其toString函数

举个例子

以下代码来自脚本之家的相关文章


[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. var bbb = {  
  2.  i: 10,  
  3.  toString: function() {  
  4.   console.log('toString');  
  5.   return this.i;  
  6.  },  
  7.  valueOf: function() {  
  8.   console.log('valueOf');  
  9.   return this.i;  
  10.  }  
  11. }  
  12. alert(bbb);// 10 toString  
  13. alert(+bbb); // 10 valueOf  
  14. alert(''+bbb); // 10 valueOf  
  15. alert(String(bbb)); // 10 toString  
  16. alert(Number(bbb)); // 10 valueOf  
  17. alert(bbb == '10'); // true valueOf  
  18. alert(bbb === '10'); // false  

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


在这里我说一下我的理解

valueOf的意思是返回最适合该对象类型的原始值,而toString则是将在该对象类型的原始值以字符串形式返回。


第一个

[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. alert(bbb);// 10 toString  
这里我们的alert函数需要是的字符串,所以获取的是字符串,而不是原始值,故而调用了toString

第二个

[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <span style="font-family: Arial, Helvetica, sans-serif;">alert(+bbb); // 10 valueOf</span>  

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

为了验证我们这样写

[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. var a = {  
  2.     i: 1,  
  3.     valueOf: function () {  
  4.         alert("你调用了a的valueOf函数");  
  5.         return this.i;  
  6.     },  
  7.     toString: function () {  
  8.         alert("你调用了a的toString函数");  
  9.         return this.i;  
  10.     }  
  11. };  
  12. var c = {  
  13.     i: +a,  
  14.     valueOf: function () {  
  15.         alert("你调用了c的valueOf函数");  
  16.         return this.i;  
  17.     },  
  18.     toString: function () {  
  19.         alert("你调用了c的toString函数");  
  20.         return this.i;  
  21.     }  
  22. };  
  23. alert(c);  

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


第三个

[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. alert(''+bbb); // 10 valueOf  
同理,我们可以把上一段我写的程序里面的c:+a改成c:'’+a


第四个

[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. alert(String(bbb)); // 10 toString  
String这个强制转换其实在其内部是调用了传入参数的toString函数……


第五个

[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. alert(Number(bbb)); // 10 valueOf  
这个是有区别的,因为bbb的i属性是数值类型的,如果i为11111xxxxx这样的字符串,我们就可以看到调用了bbb的toString了

呐,代码例子

[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1.     var c = {  
  2.     i: "11111xxxx",  
  3.     valueOf: function () {  
  4.         alert("你调用了c的valueOf函数");  
  5.         return this.i;  
  6.     },  
  7.     toString: function () {  
  8.         alert("你调用了c的toString函数");  
  9.         return this.i;  
  10.     }  
  11. };  
  12. alert(c);  

第六个

[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. alert(bbb == '10'); // true valueOf  
这个里面的判等的顺序是,获取原始值,然后判断两边的原始值是否相等,所以调用valueOf


第七个也就是最后一个

[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. alert(bbb === '10'); // false  
这个里面的判全等的第一个步骤是判断类型,因为类型都不一样了,所以后面什么都不会调用


讨论

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

原文例子

[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. var aa = {   
  2.  i: 10,   
  3.  toString: function() {   
  4.   console.log('toString');   
  5.   return this.i;   
  6.  }   
  7. }   
  8. alert(aa);// 10 toString   
  9. alert(+aa); // 10 toString   
  10. alert(''+aa); // 10 toString   
  11. alert(String(aa)); // 10 toString   
  12. alert(Number(aa)); // 10 toString   
  13. alert(aa == '10'); // true toString   

我的观点有些不同,重写了的toString会被未重写的其prototype的valueOf隐式调用,而不是优先调用toString。虽然结果不同,但是其实没有优先级的变化。(但是我只能证明重写了的toString会被未重写的其prototype的valueOf隐式调用,却不能证明未重写和重写后的优先级变化读者如果完成了验证请教教我,我的js上周一才开始学。以下是例子)

[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. var a = {  
  2.         i: 1,  
  3.         valueOf: function () {  
  4.             alert("你调用了a的valueOf函数");  
  5.             return Object.prototype.valueOf();  
  6.         },  
  7.         toString: function () {  
  8.             alert("你调用了a的toString函数");  
  9.             return this.i;  
  10.         }  
  11.     };  
  12.      
  13.     alert(+a);  
  14.     alert(''+a);  

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


另一个原文的例子

[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. var bb = {   
  2.  i: 10,   
  3.  valueOf: function() {   
  4.   console.log('valueOf');   
  5.   return this.i;   
  6.  }   
  7. }  
  8. alert(bb);// [object Object]   
  9. alert(+bb); // 10 valueOf   
  10. alert(''+bb); // 10 valueOf   
  11. alert(String(bb)); // [object Object]   
  12. alert(Number(bb)); // 10 valueOf   
  13. alert(bb == '10'); // true valueOf   

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


[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. function toString() {  
  2.     return '[object Object]';  
  3. }  


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



总结

所以那篇的结论并不是最根本的问题,最根本的问题是到底操作对象所处的环境是什么样的。

如果要求的是原始值那么就会调用valueOf,如果要求的是字符串那么就会调用toString。



转自:http://blog.csdn.net/cct418/article/details/50889987

  • 4
    点赞
  • 0
    评论
  • 0
    收藏
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值