js中的valueOf和toString

  目录

js中的valueOf和toString

js中的valueOf和toString

valueOf和toSring两个函数是除null和undefined两种数据类型以外其他五种数据类型(number/string/bool/object/symbol)原型链上共有的函数,那么这两个函数主要是用来干什么的呢?司徒正美大神给出的答案是:值运算和显示问题,一般在隐式类型转换时会自动调用(经典面试题见备注3)。

例1:

如果同时重写了valueOf和toString方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var aaa = {
i: 10,
valueOf: function() {
console.log('valueOf')
return this.i+30;
},
toString: function() {
console.log('toString')
return this.i+10;
}
}
console.log(aaa > 20); // valueOf true
console.log('' + aaa); // valueOf 40
console.log(++aaa); // valueOf 41
console.log(+aaa); // valueOf 40
alert(aaa); // toString 20
console.log(aaa == 40) //valueOf true
console.log(String(aaa)) // toString 20

总结:涉及到操作符的问题,valueOf的优先级比toString的优先级高,涉及到显示问题,toString方法优先级比valueOf方法高。

例2:

如果只是重写了toString方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var aaa = {
i: 10,
toString: function() {
console.log('toString')
return this.i+10;
}
}
console.log(aaa > 20); // toString false
console.log('' + aaa); // toString 20
console.log(++aaa); // toString 21
console.log(+aaa); // toSring 20
alert(aaa); // toString 20
console.log(aaa == 20) //toString true
console.log(String(aaa)) // toString 20

总结:只重写了toString方法的话,toString方法比原型链上的valueOf方法优先级高。

例3

如果只重写了valueOf方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var aaa = {
i: 10,
valueOf: function() {
console.log('valueOf')
return this.i+30;
}
}
console.log(aaa > 20); // valueOf true
console.log('' + aaa); // valueOf 40
console.log(++aaa); // valueOf 41
console.log(+aaa); // valueOf 40
alert(aaa); // [object Object]
console.log(aaa == 20) //valueOf false
console.log(String(aaa)) // [object Object]

总结:只重写了valueOf方法的话,涉及到值运算优先调用valueOf方法,涉及到显示问题还是优先调用原型链上的toString方法。

备注

针对一般没有对valueOf和toString方法进行重写的情况:
1.对除null和undefined(这两种类型的原型上没有valueOf方法)以外的数据类型调用valueOf方法,得到的都是数据本身。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var a = 1
var aa = a.valueOf()
aa === a //true

var b = 'a'
var bb = b.valueOf()
bb ===b //true

var c = true
var cc = c.valueOf()
cc === c //true

var obj = {name: 'age'}
var objobj = obj.valueOf()
obj === objobj //true

var s = Symbol()
var ss = s.valueOf()
ss === s //true

2.对number/string/bool/symbol类型数据调用toString方法得到的是对应的字符串,对object类型数据调用toString的方法得到的是”[object Object]”,null和undefined两种数据类型的原型链上没有toString方法。

1
2
3
4
5
var aaa = a.toString() // "1"
var bbb = b.toString() // "a"
var ccc = c.toString() // "true"
var objobjobj = obj.toString() //"[object Object]"
var sss = s.toString() //"Symbol()"

3.也可以得到一个经典前端面试题的一种解法,如何能够使得下列的表达式返回true

1
a==1 && a==2 && a==3

解法如下:

1
2
3
4
5
6
7
var a = {
i: 1,
valueOf: function() {
return a.i++
}
}
a==1 && a==2 && a==3 //返回true

以上重写了valueOf函数,比较运算时会优先调用该函数。当然,如果重写toString方法的话,比较运算也会优先调用该toString函数,因此可以到达同样的效果。
还有其他一种常见的解法:

1
2
3
4
5
6
7
var val = 1
Object.defineProperty(window, 'a', {
get() {
return val++
}
})
a==1 && a==2 && a==3 //同样返回true