JavaScript toString valueof

140 阅读2分钟

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

toString

调用

  • 表示对象的时候,变成[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') }'
  • 某种场合toStringtypeof & 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]
  • 隐式转换

    • 操作符一边为对象,则会先调用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')

重写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

valueOf

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

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

两者区别

共同点:在输出对象时会自动调用

不同点

  • 默认返回值不同,且存在优先级关系

  • 对象转换时,将优先调用toString方法

    • 没有重写 toString,将调用 valueOf 方法

    • 两个方法都没有重写,按ObjecttoString输出

  • 强转字符串类型时,将优先调用 toString 方法,强转为数字时优先调用 valueOf

  • 使用运算操作符时,valueOf的优先级高于toString

  • 数值运算中,优先调用了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)
class A {
    valueOf() {
        return 2
    }
}
let a = new A()

Object.prototype.toString = null; 

console.log(String(a))  // 2        => (valueOf)
console.log(Number(a))  // 2        => (valueOf)
console.log(a + '22')   // '222'    => (valueOf)
console.log(a == 2)     // true     => (valueOf)

[Symbol.toPrimitive]

  • 当做一个函数

    • 内置的 Symbol 值
  • 作用:同valueOf()toString()一样,但是优先级要高于这两者

  • 该函数被调用时,会被传递一个字符串参数hint,表示当前运算的模式,一共有三种模式

    • string:字符串类型

    • number:数字类型

    • default:默认

class A {
    constructor(count) {
        this.count = count
    }
    valueOf() {
        return 2
    }
    toString() {
        return '哈哈哈'
    }
    // 我在这里
    [Symbol.toPrimitive](hint) {
        if (hint == "number") {
            return 10;
        }
        if (hint == "string") {
            return "Hello Libai";
        }
        return true;
    }
}

const a = new A(10)

console.log(`${a}`)     // 'Hello Libai' => (hint == "string")
console.log(String(a))  // 'Hello Libai' => (hint == "string")
console.log(+a)         // 10            => (hint == "number")
console.log(a * 20)     // 200           => (hint == "number")
console.log(a / 20)     // 0.5           => (hint == "number")
console.log(Number(a))  // 10            => (hint == "number")
console.log(a + '22')   // 'true22'      => (hint == "default")
console.log(a == 10)     // false        => (hint == "default")
  • 特殊的是(+)拼接符,这个属于default的模式

划重点:此方法不兼容IE

引用: juejin.cn/post/687321…