理解透toString与valueOf

1,023 阅读2分钟

参考加引用这位大佬:juejin.cn/post/687321…

1、两个方法存在的意义

  • 基本上,所有JS数据类型都拥有这两个方法,null除外。它们俩是位于原型链上的方法,也是为了解决javascript值运算与显示的问题

valueOf 和 toString 几乎都是在出现操作符(+-*/==><)时被调用(隐式转换)

2、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)精准数据类型判断

这里就不做讲解,详细可以看这篇文章:js判断数据类型的六种方式总结

(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的默认值(下面测试)
}
console.log(2 + 1)  // 3
console.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')

(4)重写toString

class A {
    constructor(count) {
        this.count = count
    }
    toString() {
        return '我有这么多钱:' + this.count
    }
}
let a = new A(100)

console.log(a)              // A{count: 100}
console.log(a.toString())   // 我有这么多钱:100
console.log(a + 1)          // 我有这么多钱:1001

3、vauleOf

返回当前对象的原始值

同样具有以上的自动调用和重写方法,其它方面有所区别

let c = [1, 2, 3]
let d = {a:2}

console.log(c.valueOf())    // [1, 2, 3]
console.log(d.valueOf())    // {a:2}

4、两者区别

  • 二者并存的情况下,在数值运算中(运算符),优先调用了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     => (严格等于不会触发隐式转换)

进一步证明

  • 先去掉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)