本文共 4118 字,大约阅读时间需要 13 分钟。
从《高级程序设计》这本书里面
- var colors = ["red", "blue", "green"];
- alert(colors.toString());
- alert(colors.valueOf());
- alert(colors);
的这个例子,我们会有一个非常大的疑问
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());
(坑爹阿csdn,朕的代码缩进)
来来,猜猜结果。
结果就是我们会看到“你调用了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);
- alert(+bbb);
- alert(''+bbb);
- alert(String(bbb));
- alert(Number(bbb));
- alert(bbb == '10');
- alert(bbb === '10');
他的文章讲的不是很清楚,为什么在我们重写了代码以后就会出现这样的情况
在这里我说一下我的理解
valueOf的意思是返回最适合该对象类型的原始值,而toString则是将在该对象类型的原始值以字符串形式返回。
第一个
这里我们的alert函数需要是的字符串,所以获取的是字符串,而不是原始值,故而调用了toString
第二个
- <span style="font-family: Arial, Helvetica, sans-serif;">alert(+bbb);
同理,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
第三个
同理,我们可以把上一段我写的程序里面的c:+a改成c:'’+a
第四个
String这个强制转换其实在其内部是调用了传入参数的toString函数……
第五个
这个是有区别的,因为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);
第六个
这个里面的判等的顺序是,获取原始值,然后判断两边的原始值是否相等,所以调用valueOf
第七个也就是最后一个
这个里面的判全等的第一个步骤是判断类型,因为类型都不一样了,所以后面什么都不会调用
讨论
另外,对于原文的这句话“ 在进行对象转换时(例如:alert(a)),将优先调用toString方法,如若没有重写toString将调用valueOf方法,如果两方法都不没有重写,但按Object的toString输出。”我不是很认同
原文例子
- var aa = {
- i: 10,
- toString: function() {
- console.log('toString');
- return this.i;
- }
- }
- alert(aa);
- alert(+aa);
- alert(''+aa);
- alert(String(aa));
- alert(Number(aa));
- alert(aa == '10');
我的观点有些不同,重写了的toString会被未重写的其prototype的valueOf隐式调用,而不是优先调用toString。虽然结果不同,但是其实没有优先级的变化。(但是我只能证明重写了的toString会被未重写的其prototype的valueOf隐式调用,却不能证明未重写和重写后的优先级变化读者如果完成了验证请教教我,我的js上周一才开始学。以下是例子)
- 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);
- alert(+bb);
- alert(''+bb);
- alert(String(bb));
- alert(Number(bb));
- alert(bb == '10');
而valueOf被重写以后,这个bb的对象没有toString,自然就会调用其prototype的toString,而那个toString的内容必然是
- function toString() {
- return '[object Object]';
- }
,所以其实这个验证并没有什么意义。无论重写哪个函数最终的优先级都没变。
总结
所以那篇的结论并不是最根本的问题,最根本的问题是到底操作对象所处的环境是什么样的。
如果要求的是原始值那么就会调用valueOf,如果要求的是字符串那么就会调用toString。
转载地址:http://eshni.baihongyu.com/