一般的对象,都从
Object.prototype
上继承到 toString
和 valueOf
方法,如果是数组,则从 Array.prototype
上继承得到 toString
和 valueOf
方法。前者的 toString 简单的返回
[object Object]
、其 valueOf 返回其自身,而对于后者,toString 则有意义的多,比如 [1, 2, 3].toString()
会返回 1,2,3
、其 valueOf
与前者一样返回其自身。一般来说,绝大部分的对象,都会继承到 toString 和 valueOf 方法,而且如果没有此方法,JavaScript 将在对引用类型做类型转换的时候会报错。
比如计算表达式
[1, 2] == 233
的时候,这时 JavaScript 会自动调用 valueOf
和 toString
,也就是说 [1, 2] == '1,2'
结果将会是 true
如果要研究 toString 和 valueOf 得先创造没有这两个函数的对象。
# 创建没有 toString 和 valueOf 的对象 ↵
这很简单,利用
Object.create(null)
即可。00// Person.js 01var PP = Object.create(null); 02 03function Person(n, age){ 04 this.name = n; 05 this.age = age; 06} 07 08Person.prototype = PP; 09 10// for require 11module.exports = Person;
接下来 自己为
Person
的原型写一些方法:00// Person.js 01 02PP.toString = function(){ 03 return `NAME: ${this.name}, AGE: ${this.age}`; 04} 05 06PP.valueOf = function(){ 07 return [ 08 this.name, 09 this.age 10 ]; 11} 12 13PP.sayName = function(){ 14 console.log(this.name); 15}
# 使用 Person 构造器 ↵
00// index.js 01const Person = require('./Person.js'); 02 03var eczn = new Person('eczn', 20); 04var xiao = new Person('xiao', 19); 05 06console.log(eczn + xiao); 07// => 08// "NAME: eczn, AGE: 20NAME: xiao, AGE: 19"
结果输出
NAME: eczn, AGE: 20NAME: xiao, AGE: 19
符合预期。
类型转换
# +new Date() 的原理 ↵
+(new Date()) 其实就是调用了 Date.prototype 上的 valueOf 方法,从而得到时间戳。
Date 实例的 toString 也是类似,根据时间戳把对应的字符串显示出来。
00+new Date(); 01// => 02// 1500550679669
# == 中的 valueOf ↵
JavaScript
在处理引用类型的 ==
比较上,做法是调用对象的 valueOf
从而得到表征对象的原始值然后进行比较的,如果没有 valueOf
方法或者 valueOf 仅仅返回对象自己,则转而调用 toString
。因此如下表达式将会返回
true
00({}) == '[object Object]' 01// => 02// true
而且如果对象没有
valueOf
和 toString
方法时,在使用 == 的时候会报错:00var noValueOf = Object.create(null); 01noValueOf == 233; 02// => 03// Uncaught TypeError: Cannot convert object to primitive value
错误提示:Cannot convert object to primitive value,无法将对象转化成基本类型值
此外,在对引用类型做算数运算的时候也会调用
valueOf
和 toString
方法来将引用类型转化成原始类型进行比较。因此,利用上述性质,完全可以自定义对象的运算,以上述的
Person
为例,对其构建关于年龄大小的比较运算,需要重写原型上的 valueOf :00var PP2 = Object.create(null); 01 02function Person2(n, age){ 03 this.name = n; 04 this.age = age; 05} 06 07Person2.prototype = PP2; 08 09PP2.valueOf = function(){ 10 return this.age; 11} 12 13PP2.sayOlderThan = function(others){ 14 console.log(`${this.name}: i am olader than ${others.name}`) 15}
如下方式使用:
00var eczn = new Person2('eczn', 20); 01var xiao = new Person2('xiao', 19); 02 03if (eczn > xiao){ 04 eczn.sayOlderThan(xiao); 05} else { 06 xiao.sayOlderThan(eczn); 07}

eczn 比 xiao 大
# 更抽象、更高阶 ↵
这样一来,JavaScript 将会有更加灵活的面向对象,我们可以定义
对象间计算
,以便进行更高阶的抽象。==
运算符或许不是传闻中的那么不堪,在上述情况下,是非常有用的一种特性。