基本上,所有JS数据类型都拥有这两个方法,null除外。它们俩是位于原型链上的方法,也是为了解决javascript值运算与显示的问题。
valueOf 和 toString 几乎都是在出现操作符(+-*/==><)时被调用(隐式转换)。
比如 字符串 + 数字 ,数字会被自动转为字符串
'3' + 3 //'33'
toString
返回一个表示该对象的字符串,当对象表示为文本值或以期望的字符串方式被引用时,toString方法被自动调用。
1. 手动调用看看什么效果
嗯,跟介绍的一样,没骗人,全部都转成了字符串。
比较特殊的地方就是,
表示对象的时候,变成[object Object],
表示数组的时候,就变成数组内容以逗号连接的字符串,相当于Array.join(',')。
let a = {}let b = [1, 2, 3]let c = '123'let d = function(){ console.log('fn') }console.log(a.toString()) // '[object Object]'console.log(b.toString()) // '1,2,3'console.log(c.toString()) // '123'console.log(d.toString()) // 'function(){ console.log('fn') }'
2. 最精准的类型判断
这种属于更精确的判断方式,在某种场合会比使用 typeof & instanceof 来的更高效和准确些。
toString.call(()=>{}) // [object Function]toString.call({}) // [object Object]toString.call([]) // [object Array]toString.call('') // [object String]toString.call(22) // [object Number]toString.call(undefined) // [object undefined]toString.call(null) // [object null]toString.call(new Date) // [object Date]toString.call(Math) // [object Math]toString.call(window) // [object Window]
3. 什么时候会自动调用呢
使用操作符的时候,如果其中一边为对象,则会先调用toSting方法,也就是隐式转换,然后再进行操作。
let c = [1, 2, 3]let d = {a:2}Object.prototype.toString = function(){console.log('Object')}Array.prototype.toString = function(){console.log('Array')return this.join(',') // 返回toString的默认值(下面测试)}Number.prototype.toString = function(){console.log('Number')}String.prototype.toString = function(){console.log('String')}console.log(2 + 1) // 3console.log('s') // 's'console.log('s'+2) // 's2'console.log(c < 2) // false (一次 => 'Array')console.log(c + c) // "1,2,31,2,3" (两次 => 'Array')console.log(d > d) // false (两次 => 'Object')
valueOf
返回当前对象的原始值。
具体功能与toString大同小异,同样具有以上的自动调用和重写方法。
这里就没什么好说的了,主要为两者间的区别
let c = [1, 2, 3]let d = {a:2}console.log(c.valueOf()) // [1, 2, 3]console.log(d.valueOf()) // {a:2}
两者区别
- 共同点:在输出对象时会自动调用。
- 不同点:默认返回值不同,且存在优先级关系。
二者并存的情况下,
在数值运算中,优先调用了valueOf,字符串运算中,
优先调用了toString。
class A {valueOf() {return 2}toString() {return '哈哈哈'}}let a = new A()console.log(String(a)) // '哈哈哈' => (toString)console.log(Number(a)) // 2 => (valueOf)console.log(a + '22') // '222' => (valueOf)console.log(a == 2) // true => (valueOf)console.log(a === 2) // false => (严格等于不会触发隐式转换)
结果给人的感觉是,如果转换为字符串时调用toString方法,如果是转换为数值时则调用valueOf方法。
但其中的 a + '22' 很不和谐,字符串合拼应该是调用toString方法。为了追究真相,我们需要更严谨的实验。
暂且先把 valueOf 方法去掉
class A {toString() {return '哈哈哈'}}let a = new A()console.log(String(a)) // '哈哈哈' => (toString)console.log(Number(a)) // NaN => (toString)console.log(a + '22') // '哈哈哈22' => (toString)console.log(a == 2) // false => (toString)
去掉 toString 方法看看
class A {valueOf() {return 2}}let a = new A()console.log(String(a)) // '[object Object]' => (toString)console.log(Number(a)) // 2 => (valueOf)console.log(a + '22') // '222' => (valueOf)console.log(a == 2) // true => (valueOf)
总结:
valueOf偏向于运算,toString偏向于显示。
