Number()和new Number()的區別以及造個簡單的輪子


  看JavaScript文檔的時候注意到了這種用法 var n1 = Number(123); , 冒出的第一個疑問就是和 var n2 = new Number(123); 有什么區別呢? 

 

  首先用typeof做下探測, n1是number而n2是object, 他們的本質區別就是type不同.

 

  那么有趣的問題來了, Number內部肯定知道是怎么調用的它. 假設在沒有Number的情況下, 如果我要實現個類似的類應該怎么做呢?

 

  最先想到的就是根據caller來區分, 但在實驗的過程中發現兩個問題:

  1. 全局調用的時候沒有caller
  2. 就算知道caller也無法區分它是function調用還是構造對象

 

  所以caller這條路就走不通了, 既然需要在運行期區分, 那么該"真愛" this 登場了. this指向當前構造的對象, 我就可以區分是function調用還是構造對象了.

 

  我的新輪子命名為WNumber, 思路理清楚后就剩施工了. 為了更接近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的, 但我們的 123 == new WNumber('123') 卻返回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 = /^([\+\-]?)([0-9]+)$/.exec(i);//正則表達式抓取正負符號和數字的文本值
            if(regR !== null){
                var nstr = regR[2];//數字的文本值,相當於Java的group(2)
                var nstrlen = nstr.length;
                var nResult = arguments.callee(0);//callee就是本function
                for(idx in nstr){
                    //通過計算ASCII碼的差值轉換成數字, 見后記
                    nResult += (nstr[idx].charCodeAt(0) - "0".charCodeAt(0)) * 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;
        }
    }

 

 

后記: string快速轉換成number的方法是 "123" * 1 = 123 , 但這是語法糖, 實際上是 Number("123") * 1 , 所以我選擇計算ASCII碼的差值.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM