js valueOf
toString的区别
valueOf():返回最适合该对象类型的原始值;
toString(): 将该对象的原始值以字符串形式返回。
在数值运算里,会优先调用valueOf(),如a + b;
在字符串运算里,会优先调用toString(),如alert(c)。
知乎来源
我在网上找到的其他例子,放在crhome里面跑,或者nodejsV7.7.2都是不同的
所以有理由相信,之前的js实现跟当前流行的是不一样的,下面以nodejs为主
var c = {
i: 10,
valueOf: function () {
console.log("valueOf --->")
return this.i + 30;
},
toString: function () {
console.log("toString --->")
return this.i + 10;
}
}
console.log(c > 20)
console.log(+c)
console.log(c)
console.log(String(c));
console.log(Number(c));
//output
valueOf --->
true
valueOf --->
40
valueOf --->
{ [Number: 40]
i: 10,
valueOf: [Function: valueOf],
toString: [Function: toString] }
toString --->
20
valueOf --->
40
从上面结果可以看到,当对象尝试+、>等跟数字运算符相关的,都是优先调用Valueof的,而String强转才调用toString
算数运算符:+ - * / % ++ --
关系运算符:== != > >= < <=
逻辑运算符:&& || ! ^ & |
位运算符:& | ~ ^ >> << >>>
难题
遇到过这样的一道难题,大概让写出满足下面条件的函数
console.log(
f(10)(10) == 20 &&
f(10)(20)(50) == 80 &&
f(10)(20)(50)(100) == 180 &&
f(10, 20, 50, 101) == 181 &&
f(10, 20, 50)(102) == 182
)
上述为true
是的如果f返回的是一个数字,那么例子2的f(3)可能再去调用f(3)(2)呢?答案就是这个valueOf(如果函数对象没有toString的话,其实用toString也可以,如果没有valueOf的话,回去尝试调用toString)
知乎上某答案区别
为什么valueOf比toString好呢?贴一段v8代码Object -> Primitive的过程:如果是Date类型的话,走DefaultString,否则走DefaultNumberDefaultNumber会判断Object有木有valueOf方法,有的话,直接调用return,没有的话去判断toString方法
/* -------------------------------------
- - - C o n v e r s i o n s - - -
-------------------------------------
*/
// ECMA-262, section 9.1, page 30. Use null/undefined for no hint,
// (1) for number hint, and (2) for string hint.
function ToPrimitive(x, hint) {
// Fast case check.
if (IS_STRING(x)) return x;
// Normal behavior.
if (!IS_SPEC_OBJECT(x)) return x;
if (IS_SYMBOL_WRAPPER(x)) throw MakeTypeError('symbol_to_primitive', []);
if (hint == NO_HINT) hint = (IS_DATE(x)) ? STRING_HINT : NUMBER_HINT;
return (hint == NUMBER_HINT) ? %DefaultNumber(x) : %DefaultString(x);
}
// ECMA-262, section 8.6.2.6, page 28.
function DefaultNumber(x) {
if (!IS_SYMBOL_WRAPPER(x)) {
var valueOf = x.valueOf;
if (IS_SPEC_FUNCTION(valueOf)) {
var v = %_CallFunction(x, valueOf);
if (%IsPrimitive(v)) return v;
}
var toString = x.toString;
if (IS_SPEC_FUNCTION(toString)) {
var s = %_CallFunction(x, toString);
if (%IsPrimitive(s)) return s;
}
}
throw %MakeTypeError('cannot_convert_to_primitive', []);
}
当然我这道题跟上面那道答案的题是有点不同的,不过本质上是一样的
答案如下:
function f(){
let sum = 0;
for(i in arguments) {
sum += arguments[i];
}
function m(){
for (i in arguments) {
sum += arguments[i];
}
return m;
}
m.valueOf=function(){
return sum;
}
return m;
}
这东西叫柯里化,本质上如果直接打印f(10)其实还是打印对象本身
console.log(f(10))
//output
{ [Number: 10] valueOf: [Function] }