有一道面試題是:
實現一個函數,運算結果可以滿足如下預期結果:
add(1)(2) //3
add(1,2,3)(10) //16
add(1)(2)(3)(4)(5) //15
其中一種解法:
function add(){
console.log("進入add");
var args = Array.prototype.slice.call(arguments);
console.log(args);
var fn = function () {
var arg_fn = Array.prototype.slice.call(arguments);
console.log('調用fn');
console.log(arg_fn);
return add.apply(null,args.concat(arg_fn));
}
fn.valueOf = function () {
console.log('調用valueOf()');
return args.reduce(function (a,b) {
console.log('調用valueOf(),返回%d+%d=%d',a,b,a+b);
return a+b;
})
}
return fn;
}
console.log(add(2)(3,4);
// add(1)(2);
// add(3,4,5)(6);
剛看到這個解決辦法會覺得很奇怪,fn.valueOf()沒有被調用過,這樣寫怎么能成功解決呢?
原因:
JavaScript調用valueOf()方法把對象轉換成原始類型的值(數值、字符串和布爾值)。并且往往valueOf()方法會被JavaScript自動調用。
valueOf()和toString()在特定場合下會自動調用!!!
下面來說一說類型轉換:
原始類型
JavaScript的幾種原始類型,除去Object和Symbol,有以下幾種:
- Number
- String
- Boolean
- Undefined
- Null
在JavaScript進行對比或者各種運算的時候會把對象轉換成這些類型,從而進行后續操作。
String類型轉換
在某個操作或者運算需要字符串而該對象又不是字符串的時候,會觸發該對象的String轉換,會將非字符串的類型嘗試自動轉換為String類型。系統內部會自動調用toString函數。
var obj = {name:'Wonder'};
var str = '123'+obj;
console.log(str); //123[object Object]
轉換規則:
- 如果toString方法存在并且返回原始類型,返回toString的結果。
- 如果toString方法不存在或者返回的不是原始類型,調用valueOf方法,如果valueOf方法存在,并且返回的是原始類型數據,返回valueOf的結果
- 其他情況,拋出錯誤。
上面的例子實際上是:
var obj = {name:'Wonder'};
var str = '123'+obj.toString();
//obj.toString的值是[object Object]
如果我們改寫對象的toString,valueOf方法:
var obj = {
toString:function(){
console.log('調用了toString');
return {};
},
valueOf:function(){
console.log('調用了valueOf');
return '10';
}
}
console.log(obj);
//調用了toString
//調用了valueOf
//10
Number類型轉換
以下會發生Number類型轉換:
- 調用Number()函數,強制進行Number類型轉換
- 調用Math.sqrt()這類參數需要Number類型的方法
- obj == 1,進行對比的時候
- obj+1,進行運算的時候
與String類型轉換相似,但是Number類型剛好反過來,先查詢自身的valueOf方法,再查詢自己toString方法。
轉換規則:
- 如果valueOf方法存在并且返回原始類型,返回valueOf的結果。
- 如果valueOf方法不存在或者返回的不是原始類型,調用toString方法,如果toString方法存在,并且返回的是原始類型數據,返回toString的結果
- 其他情況,拋出錯誤。
Boolean轉換
什么時候會進行布爾轉換呢?
- 布爾比較時
- if(obj),while(obj)等判斷時
轉換規則:
除了下述 6 個值轉換結果為 false,其他全部為 true:
- undefined
- null
- -0
- 0或+0
- NaN
- ”(空字符串)