2017-07-20
类型转换
toString 与 valueOf
一般的对象,都从 Object.prototype 上继承到 toStringvalueOf 方法,如果是数组,则从 Array.prototype 上继承得到 toStringvalueOf 方法。
前者的 toString 简单的返回 [object Object] 、其 valueOf 返回其自身,而对于后者,toString 则有意义的多,比如 [1, 2, 3].toString() 会返回 1,2,3 、其 valueOf 与前者一样返回其自身。

一般来说,绝大部分的对象,都会继承到 toString 和 valueOf 方法,而且如果没有此方法,JavaScript 将在对引用类型做类型转换的时候会报错。
比如计算表达式 [1, 2] == 233 的时候,这时 JavaScript 会自动调用 valueOftoString ,也就是说 [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
而且如果对象没有 valueOftoString 方法时,在使用 == 的时候会报错:
00var noValueOf = Object.create(null); 
01noValueOf == 233; 
02// => 
03// Uncaught TypeError: Cannot convert object to primitive value
错误提示:Cannot convert object to primitive value,无法将对象转化成基本类型值
此外,在对引用类型做算数运算的时候也会调用 valueOftoString 方法来将引用类型转化成原始类型进行比较。
因此,利用上述性质,完全可以自定义对象的运算,以上述的 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 大
eczn 比 xiao 大

# 更抽象、更高阶

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




回到顶部