看MDN Beginners文檔的時候註意到了這種用法 var n1 = Number(123); , 冒出的第一個疑問就是和 var n2 = new Number(123); 有什麼區別呢? 首先用typeof做下探測, n1是number而n2是object, 他們的本質區別就是type不同. ...
看MDN Beginners文檔的時候註意到了這種用法 var n1 = Number(123); , 冒出的第一個疑問就是和 var n2 = new Number(123); 有什麼區別呢?
首先用typeof做下探測, n1是number而n2是object, 他們的本質區別就是type不同.
那麼有趣的問題來了, Number內部肯定知道是怎麼調用的它, 那是怎麼實現的呢?
最先想到的就是根據caller來區分, 但在實驗的過程中發現兩個問題:
- 全局調用的時候沒有caller
- 就算知道caller也無法區分它是function調用還是構造對象
既然需要在運行期區分, 那麼該"真愛" this 登場了
萬事俱備擼起袖子開乾, But...先等等, 在開工前先用測試數據探測下Number的行為:
console.log(Number(123)); //123
console.log(Number(+123)); //123
console.log(Number(-123)); //-123
console.log(Number("123")); //123
console.log(Number("+123")); //123
console.log(Number("-123")); //-123
console.log(Number("abc123")); //NaN
console.log(Number(NaN)); //NaN
console.log(new Number(123)); //save as above except type
console.log(new Number(+123));
console.log(new Number(-123));
console.log(new Number("123"));
console.log(new Number("+123"));
console.log(new Number("-123"));
console.log(new Number("abc123"));
console.log(new Number(NaN));
我們的簡單實現命名為WNumber, 測試過程發現 123 == new Number('123') 是返回true的, 但我們的WNumber卻返回false, 難道瀏覽器不給WNumber國民待遇?
首先瀏覽器是不可能把123 auto-box成Number對象的, 因為兩個對象==是false的, 所以肯定是把Number對象auto-unbox成原始type(值type). 查了一下對象剛好有個valueOf()方法用來返回這個對象代表的原始值. (後來測試過程中發現valueOf()或toString()實現任一一個方法都能讓瀏覽器返回true)
下麵是WNumber的源碼
function WNumber(i){
var primitiveValue = 0;
if(typeof i === "number"){
primitiveValue = i;
}else{
var regR = /^([\+\-]?)([1-9][0-9]*)$/.exec(i);
if(regR !== null){
var nstrlen = regR[2].length;
var nResult = arguments.callee(0);
for(idx in regR[2]){
nResult += regR[2][idx]*Math.pow(10, nstrlen - idx -1);
}
if(regR[1] === '-'){
primitiveValue = -nResult;
}else{
primitiveValue = nResult;
}
}else{
primitiveValue = NaN;
}
}
if(this instanceof WNumber){
//construct object
this.valueOf = function(){
return primitiveValue;
}
this.toString = function(){
return primitiveValue + '';
}
return this;
}else{
//invoke as function
return primitiveValue;
}
}