您的位置:首页 > Web前端 > JavaScript

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

2016-07-26 19:20 597 查看
从《JavaScript高级程序设计》这本书里面

[javascript] view
plain copy

 





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()区别到底是什么?

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

[javascript] view
plain copy

 





var arr = [1,2,3];  

alert(Array.isArray(arr.valueOf()));  

alert(Array.isArray(arr.toString()));  

猜猜结果是怎么样的?

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

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

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

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

什么?你不信?

那好吧,我们来测试一下

[javascript] view
plain copy

 





var arr = [1,2,3];  

arr.toString = function () {  

    alert("你调用了toString函数");  

}  

alert(arr.valueOf());  

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

来来,猜猜结果。

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

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

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

举个例子

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

[javascript] view
plain copy

 





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则是将在该对象类型的原始值以字符串形式返回。

第一个

[javascript] view
plain copy

 





alert(bbb);// 10 toString  

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

第二个

[javascript] view
plain copy

 





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

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

为了验证我们这样写

[javascript] view
plain copy

 





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

第三个

[javascript] view
plain copy

 





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

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

第四个

[javascript] view
plain copy

 





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

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

第五个

[javascript] view
plain copy

 





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

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

呐,代码例子

[javascript] view
plain copy

 





    var c = {  

    i: "11111xxxx",  

    valueOf: function () {  

        alert("你调用了c的valueOf函数");  

        return this.i;  

    },  

    toString: function () {  

        alert("你调用了c的toString函数");  

        return this.i;  

    }  

};  

alert(c);  

第六个

[javascript] view
plain copy

 





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

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

第七个也就是最后一个

[javascript] view
plain copy

 





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

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

讨论

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

原文例子

[javascript] view
plain copy

 





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

[javascript] view
plain copy

 





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隐式调用。

另一个原文的例子

[javascript] view
plain copy

 





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的内容必然是

[javascript] view
plain copy

 





function toString() {  

    return '[object Object]';  

}  

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

总结

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

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

转自:http://blog.csdn.net/cct418/article/details/50889987
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息