别再混淆了!JS类型转换底层:valueOf vs toString vs Symbol.toPrimitive 详解
js获取对象值的方法有三种valueOf() 、toString()、symbol.toPrimitive这些其实是类型转换的问题;三种方式本质上略微不同;
我们知道在js中,'一切皆为对象'。每个对象都有一个toString()方法和valueOf方法,其中toString()方法返回一个表示该对象的字符串,valueOf 方法返回该对象的原始值。
一、valueOf() 与 toString()
基本类型的情况下:
const str = "hello",n = 123,bool = true;
console.log(typeof(str.toString()) + "_" + str.toString()) //string_hello
console.log(typeof(n.toString()) + "_" + n.toString() ) //string_123
console.log(typeof(bool.toString()) + "_" + bool.toString()) //string_true
console.log(typeof(str.valueOf()) + "_" + str.valueOf()) //string_hello
console.log(typeof(n.valueOf()) + "_" + n.valueOf()) //number_123
console.log(typeof(bool.valueOf()) + "_" + bool.valueOf()) //boolean_true
// valueOf
console.log(str.valueOf() === str) // true
console.log(n.valueOf() === n) // true
console.log(bool.valueOf() === bool) // true
// toString
console.log(str.toString() === str) // true
console.log(n.toString() === n) // false
console.log(bool.toString() === bool) // false
toString 方法对于值类型数据使用而言,其效果相当于类型转换,将原类型转为字符串。
valueOf 方法对于值类型数据使用而言,其效果将相当于返回原数据。
引用类型的情况下:
var obj = {};
console.log(obj.toString()); //[object Object] 返回对象类型
console.log(obj.valueOf()); //{} 返回对象本身
综合例子:
let test = {
i: 10,
toString: function() {
console.log('toString');
return this.i;
},
valueOf: function() {
console.log('valueOf');
return this.i;
}
}
console.log(test); // { I:10, toString: f, valueOf: f }
console.log(+test); // 10 valueOf
console.log('' + test); // 10 valueOf
console.log(String(test)); // 10 toString
console.log(Number(test)); // 10 valueOf
console.log(test == '10'); // true valueOf
console.log(test == '10'); // true valueOf
console.log(test === '10'); // false
个人理解:
带有运算符的获取值的方式都会走valueOf()方法;强转字符串的时候走toString()方法;
二、toString() 和 String()
-
toString()
-
toString()可以将所有的数据都转换为字符串,但是要排除null和undefined -
null和undefined不能转换为字符串,null和undefined调用toString()方法会报错 - 如果当前数据为数字类型,则
toString()括号中的可以写一个数字,代表进制,可以将数字转化为对应进制字符串。
-
var num = 123;
console.log(num.toString()+'_'+ typeof(num.toString())); //123_string
console.log(num.toString(2)+'_'+typeof(num.toString())); //1111011_string
console.log(num.toString(8)+'_'+typeof(num.toString())); //173_string
console.log(num.toString(16)+'_'+typeof(num.toString())); //7b_string
-
String()
String()可以将null和undefined转换为字符串,但是没法转进制字符串。
三、Symbol.toPrimitive
对象的Symbol.toPrimitive属性。指向一个方法。该对象被转化为原始类型的值时,会调用这个办法,返回该对象对应的原始类型值。 Symbol.toPrimitive被调用时,会接受一个字符串参数,表示当前运算的模式,一个有三种模式。
-
Number: 该场合需要转成数值 -
String: 该场合需要转成字符串 -
Default: 该场合可以转成数值,也可以转成字符串。
Symbol.toPrimitive在类型转换方面,优先级是最高的
const test = {
i: 10,
toString: function() {
console.log('toString');
return this.i;
},
valueOf: function() {
console.log('valueOf');
return this.i;
},
[Symbol.toPrimitive](hint) {
if(hint === 'number'){
console.log('Number场景');
return 123;
}
if(hint === 'string'){
console.log('String场景');
return 'str';
}
if(hint === 'default'){
console.log('Default 场景');
return 'default';
}
}
}
console.log(test); // { i:10, toString: f, valueOf: f, Symbol(Symbol.toPrimitive): f }
console.log(+test); // 123 Number场景
console.log(''+test); // default Default 场景
console.log(String(test)); // str String场景
console.log(Number(test)); // 123 Number场景
console.log(test == '10'); // false default场景
console.log(test === '10'); // false
上面代码中、+test中的加号命名为一元加号;+test本质就是转成数值的意思;
Tips
console.log(3 + test); // 3default Default 场景
console.log(3 - test); // -120 Number场景
console.log(3 * test); // 369 Number场景
console.log(3 / test); // 0.0243902 Number场景
以上的代码中,加减乘除都算运算符,本应都应该走Number场景,但是唯独+号走了Default场景;
四、一元加号
一元加号运算符 + 在其操作数之前,并计算其操作数;但如果尚未将其转换为数字,则尝试将其转换为数字。
console.log(+'') // 0
console.log(+true) // 1
console.log(+false) // 0
console.log(+'hello') // NaN
console.log(1 + +"2" + "2") // 32
一元加法是将某事物转换为数字的最快和首选方法,因为它不对数字执行任何其他操作。
如果它无法解析特定值,它将输出为NaN
感谢您抽出宝贵的时间观看本文;本文是JavaScript系列的第 6 篇,后续会持续更新,欢迎关注~