小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
前言
这两个属性方法,其实我们天天经常接触,有显示的和隐性的。
数据类型经常用到toString,
const toString = Object.prototype.toString
function getType(obj){
return toString.call(obj).slice(8,-1).toLowerCase();
}
getType(null) // null
getType(undefined) // undefined
上面方法null的获得的类型是 null, 可不等于typeof null的object。
更多获取数据类型的方法方式参见 判断数据类型几种方式, 里面提到大约8种方式,管饱。
但是仅仅限于这个作用吗。
valueOf 又是什么鬼,没直接用过,没事,今天一起来学习学习。
正文开始之前,一定要清楚一点,这两个方法都是原型上的方法。
Object.prototype.toString
返回一个表示该对象的字符串。
MDN文献:
默认情况下,
toString()方法被每个Object对象继承。如果此方法在自定义对象中未被覆盖,toString()返回 "[object type]",其中type是对象的类型。
({}).toString() // [object Object]
特殊注意的一点就是, 虽然null和undefined没法直接调用,
但是可以作为Object.prototype.toString.call 或者Object.prototype.toString.apply调用的参数
Object.prototype.toString.call(null) // [object Null]
Object.prototype.toString.apply(null) // [object Null]
文献中有提到,这只是此方法未被覆盖的时候,我们有时候为了特定情况,就会进行覆盖。
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.toString = function (){
return "I'am " + this.name + ", " + this.age
}
var person = new Person("tom", 18);
console.log(person + ""); // I'am Tom, 18
Object.prototype.valueOf
返回指定对象的原始值。
| ** 对象** | 返回值 |
|---|---|
| Array | 返回数组对象本身 |
| Boolean | 布尔值 |
| Date | 存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 UTC。 |
| Function | 函数本身 |
| Number | 数字值 |
| Object | 对象本身。这是默认情况 |
| String | 字符串 |
MDN关于valueOf的中文文献中:
说Math和Error没有valueOf方法,你信吗,我不信啊。
Math.valueOf() // Math {abs: ƒ, acos: ƒ, acosh: ƒ, asin: ƒ, asinh: ƒ, …}
new Math() // Uncaught TypeError: Math is not a constructor
Error.valueOf() // ƒ Error() { [native code] }
(new Error()).valueOf() // Error at <anonymous>:1:2
所以嘛,时刻保持思考,实践是检查真相的唯一真理。
同样的,valueOf也是可以改写的。
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.valueOf = function (){
return "I'am " + this.name + ", " + this.age
}
var person = new Person("tom", 18);
console.log(person + ""); // I'am Tom, 18
瞧瞧,你发现了什么?
转为原值的时候,是先走valueOf, 再走toString。
稍微调整一下代码,再看个例子:
Person.prototype.valueOf = function (){
return this.age
}
var person = new Person("tom", 18);
console.log(person + 18); // 36
纳里!!!, 刚不说了吗,转原值,先先走valueOf, 再走toString。, 这valueOf返回了原值,不就直接OK了吗
Symbol.toPrimitive
根据上面的例子,再进一步
Person.prototype[Symbol.toPrimitive] = function (){
return "I'am " + this.name + ", " + this.age
}
Person.prototype.valueOf = function (){
return this.age
}
var person = new Person("tom", 18);
console.log(person + 18); // I'am Tom, 18
哇,再修改一下优先级
- Symbol.toPrimitive
- Oject.prototye.valueOf,
- Object.prototype.toString
这里,其有一个返回原值了,就over了。, 不然接着往下调用。
看起是是对的,其实也不对。
Person.prototype.valueOf = function (){
return this.age
}
Person.prototype.toString = function (){
return this.name
}
var person = new Person("tom", 18);
console.log(`${person}`); // tom
输出是tom, 并不是 18。
正确姿势:
- Symbol.toPrimitive 优先
- 如果预期转为字符串,Object.prototype.toString
- 如果无预期转为字符串, 先走 Oject.prototye.valueOf, 再走Object.prototype.toString, 特例是Date类型,是先toString,再valueOf
验证一下特殊的Date属性:
Date.prototype.toString = function(){return 100}
Date.prototype.valueOf = function(){return 99}
new Date() == 99 // false
new Date() == 100 // true
我们把toString修改为返回一个对象, 这时候发现比较结果反了过来,valueOf生效了。
Date.prototype.toString = function(){return {}}
Date.prototype.valueOf = function(){return 99}
new Date() == 99 // true
new Date() == 100 // false
可以看出,先调用的是toString
最后巩固一下:
Person.prototype.valueOf = function (){
return this
}
Person.prototype.toString = function (){
return this.name
}
var person = new Person("tom", 18);
console.log(person + " 哈哈");
请问,输出的结果是什么呢?
小结
今天你收获了吗?