歡迎光臨
每天分享高質量文章

Javascript之旅——第八站:說說instanceof踩了一個坑

前些天寫js遇到了一個instanceof的坑,我們的頁面中有一個iframe,我在index頁面中計算得到了一個array,然後需要傳遞到Flight頁面這個巢狀的iframe中的一個函式(SearchFlight)中,作為防禦性程式設計,我需要在SearchFlight函式中進行引數檢測,也就是判斷過來的引數一定是Array型別。

一:丟擲問題

舉個例子,下麵有兩個頁面。

Index.html頁面

    
    
    

Flight.html頁面

    


    


很驚訝的發現instanceof居然不能判斷出arr是一個陣列,其實我們用肉眼可以看到,壓根它就是一個陣列,但是為什麼instanceof卻判斷不出來呢?我們知道instancof其實是一個js語法糖,我就修改成簡單點的,判斷arr.constructor是否指向Array,於是我把關鍵字改成如下形式,再來看看看效果

var flight = (function () {
            return {
                SearchFlight: function (arr) {
                    //var result = arr instanceof Array;
                    var result = arr.constructor == Array;
                    alert(result);
                }
            };
        })();


從圖上看,還真有點奇怪,明明都是function Array(),為啥都不能相等呢?不過事實就擺在眼前,容不得狡辯,只能靜下心來想一想,我們知道Array在js是屬於取用型別,既然不相等那就說明他們其實是兩個取用,對不對,並且Array是掛在window下的一個屬性,window屬性也就是一個視窗的實體,那就說明Index.html是一個window實體,Flight.html也是一個window實體,為了驗證下,我們看看兩個window是否相等?

看完圖後,答案就很明白了,以C#的思維考慮一下,既然大的window都不相等,裡面的Array屬性自然就不相等,終於問題是找到了,下麵怎麼解決呢?
二:解決問題

1.length判斷

這個很容易想到,也是最簡單的,我們知道每個陣列都有length,所以可以簡簡單單的看length是否存在就可以了,但是這個也不是萬無一失的,我們知道function中有兩個屬性length和prototype,那這就有問題了。這樣我會錯誤的把f認為是陣列
2.使用prototype的call方法來實現
這個方法有點巧妙,首先我們要知道,每一個function中都會有call方法和prototype屬性,而js在object.prototype中的tostring函式上做了一個封裝,就是呼叫tostring.call後,會傳回[object=”” constructorname]的字串格式,這裡的constructorname就是call引數的函式名,比如我們把arr傳進去,就會傳回“[object=”” array]”字串格式,這個方法也可以讓我們巧妙的判斷是否是array,但是比較遺憾的是,我們看不到這個call的內部實現,只能黑盒的記住了

贊(0)

分享創造快樂