一、toString()
- 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]。
-
[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
- 基本的 valueOf() 方法返回 this 值本身。
- 第一个输出:this指向的是p,因此输出的是p对象。(p是Person的实例对象)
- 第二个输出:将this的指向改变为{name:'this指向的是我'}这个对象,因此输出了这个对象。
三、toLocaleString
- 基本的 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 属性,如果对象内有这个属性,会被所有的强类型转换制算法优先调用。
- 接收一个参数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
六、总结
-
以上的toSting()、valueOf()、[Symbol.toPrimitive]都旨在重写(自定义)派生类对象的类型转换的逻辑。
-
原生toLocaleString内部调用toString,该方法旨在由派生对象重写,以达到其特定于语言环境的目的。
-
Symbol.toStringTag会控制toString的输出(早于es6的对象没有)。
-
什么时候调用toString/valueof
-
强制数字类型转换和强制基本类型(原始值)转换优先调用valueof,强制字符串转换优先调用toString。