一起来探究toString/toLocaleString/valueOf

237 阅读3分钟

一、toString()

  1. toString()是Object的实例方法,被每一个对象继承或重写。
  • Object.prototype.toString() 这个函数作用就是,返回当前调用者的对象类型
  • Object.prototype.toString()会返回 [object, [[class]]] 的字符串。其中[[class]]会返回es定义的对象类型,包含"Arguments", “Array”, “Boolean”, “Date”, “Error”, “Function”, “JSON”, “Math”, “Number”, “Object”, “RegExp”, 和 “String”;
  • 再加上es5新增加的返回[object Undefined]和[object Null]。
  1. [Symbol.toStringTag]可以控制toString()的输出。

    [Symbol.toStringTag]是es6增加的一个符号,可以控制toString的输出。

class Person {
            name;
            age;
            constructor(name,age){
                this.name=name
                this.age=age
                // this[Symbol.toStringTag] = 'Person'
            }
        }
        
        const p=new Person('小米',18)
        console.log(p.toString()); //[object Object]
class Person {
            name;
            age;
            constructor(name,age){
                this.name=name
                this.age=age
                this[Symbol.toStringTag] = 'Person'
            }
        }
        
        const p=new Person('小米',18)
        console.log(p.toString()); //[object Person]

二、valueOf

  1. 基本的 valueOf() 方法返回 this 值本身。
    • 第一个输出:this指向的是p,因此输出的是p对象。(p是Person的实例对象)
    • 第二个输出:将this的指向改变为{name:'this指向的是我'}这个对象,因此输出了这个对象。

三、toLocaleString

  1. 基本的 toLocaleString() 方法返回 调用toString的值。
class Person {
            name;
            age;
            constructor(name,age){
                this.name=name
                this.age=age
            }

            // 将toString方法重写,输出name
            toString(){
                return this.name
            }
        }
        
        const p=new Person('小米',18)

        console.log(p.toLocaleString()); //	小米

四、[Symbol.toPrimitive]

是内置的 symbol 属性,如果对象内有这个属性,会被所有的强类型转换制算法优先调用。

  1. 接收一个参数hint:hint 参数的具体取值由 JavaScript 解释器自动确定,hint可能为'default'、'string'、'number'。
  • default:

    • 使用一元加号运算符(+)将对象转换为原始值时。
    • 在进行关系比较(如 <, >, <=, >=)时涉及到对象和基本数据类型的混合比较。
  • string:

    • 对象作为字符串拼接的一部分,例如使用字符串连接运算符(+)或模板字符串。
    • 调用 String() 函数将对象显式转换为字符串类型。
    • 通过 console.log()console.dir() 等方式将对象输出到控制台时。
  • number:

    • 对象参与算术运算,例如进行加法、减法等操作。
    • 调用 Number() 函数将对象显式转换为数字类型。
    • 将对象用作函数的参数,且函数预期接受数字类型的参数。

五、调用优先级选择

以上几种方法我们一般不会去主动调用,一般由JavaScript解释器根据特定场景去调用不同的方法。

当对象存在[Symbol.toPrimitive]时,会被优先调用,根据hint场景返回对应的值。

当对象不存在[Symbol.toPrimitive]时,解释器也会根据场景去选择调用valueOf()还是toSting()。

  • 有 [Symbol.toPrimitive]
class Person {
            name;
            age;
            constructor(name,age){
                this.name=name
                this.age=age
            }

            // 将toString方法重写,输出name
            toString(){
                console.log("执行toString方法");                
                return this.name
            }

            valueOf(){
                console.log("执行valueOf方法");
                return this.age
            }

            [Symbol.toPrimitive](hint){
                if(hint==='string'){
                    return '场景string-姓名:'+this.name
                }else if(hint==='number'){
                    return this.age
                }else{
                    return '场景default-姓名:'+this.name+'-年龄:'+this.age
                }
            }
        }


const p=new Person('小米',18)

// 因为有[Symbol.toPrimitive],所以valueOf和toString不会被主动调用

console.log(`${p}`); //场景string-姓名:小米
console.log(+p);     //18
console.log(p+'');   //场景default-姓名:小米-年龄:18
  • 无 [Symbol.toPrimitive]

class Person {
            name;
            age;
            constructor(name,age){
                this.name=name
                this.age=age
            }

            // 将toString方法重写,输出name
            toString(){
                console.log("执行toString方法");                
                return this.name
            }

            valueOf(){
                console.log("执行valueOf方法");
                return this.age
            }
        }

const p=new Person('小米',18)

        
        console.log(`${p}`); //小米
        console.log(+p);		 //18
        console.log(p+'');   //18

六、总结

  1. 以上的toSting()、valueOf()、[Symbol.toPrimitive]都旨在重写(自定义)派生类对象的类型转换的逻辑。

  2. 原生toLocaleString内部调用toString,该方法旨在由派生对象重写,以达到其特定于语言环境的目的。

  3. Symbol.toStringTag会控制toString的输出(早于es6的对象没有)。

  4. 什么时候调用toString/valueof

  5. 强制数字类型转换和强制基本类型(原始值)转换优先调用valueof,强制字符串转换优先调用toString。