2015-11-02 96 views
1

一個奇怪的問題:關於JavaScript的原型關於JavaScript的原型

(function(w){ 
    if(!w) 
    return; 

    var TestJS = function(){ 
    }; 

    TestJS.prototype = { 

    data:{}, 
    initData:function(){ 
     this.data={ 
     val_name_1 : 1, 
     val_name_2 : 2, 
     val_name_3 : "hello-3" 
     }; 
     console.log(this.data); 
     return this; 
    }, 

    TestChildJS:{ 
     initChild:function(){ 
     console.log(TestJS); 
     console.log(TestJS.data); 
     console.log(new TestJS().data.val_name_1); 
     console.log(TestJS.data.val_name_1); 
     } 
    } 
    }; 
    window.TestJS = new TestJS(); 
})(window); 

爲什麼 'TestChildJS' 不能讓 'val_name_1'?

TestJS.initData(); 
console.log(TestJS.TestChildJS.initChild()); 

console pic

所以我必須寫我的代碼這樣的:

(function(w){ 
    if(!w) 
    return; 

    var TestJS = function(){ 
    }; 
    TestJS.prototype = { 

    data:{}, 

    initData:function(){ 
     this.data={ 
     val_name_1 : 1, 
     val_name_2 : 2, 
     val_name_3 : "hello-3" 
     }; 
     console.log(this.data); 
     this.TestChildJS.initParentData(this); 
     return this; 
    }, 

    TestChildJS:{ 
     parentData:{}, 

     initParentData:function(parent){ 
     this.parentData = parent.data; 
     return this; 
     }, 

     initChild:function(){ 
     console.log(this.parentData); 
     } 
    } 
    }; 

    window.TestJS = new TestJS(); 
})(window); 

如何使用第一種方式可以得到的第二種方式的內容?

+1

因爲'initChild'中的'TestJS'不是**'window.TestJS' ...和''TestJS()。data'中的'data',根據您的代碼的定義,直到'initData'運行的對象 –

+0

順便說一句,'(函數(窗口){...}(窗口))'是毫無意義的。如果你想明確地訪問全局對象,使用* this *,如:(function(window){...}(this))'注意在非瀏覽器主機中,* window *將是全局對象而不是一個Window對象。 – RobG

+0

@JaromandaX thx,在第一個代碼的initChild()方法中,我可以得到如下的數據:console.log(window.TestJS.data.val_name_1); –

回答

0

爲什麼'TestChildJS'無法獲得'val_name_1'?當

TestJS.initData(); 

運行時,它增加了一個數據屬性到TestJS對象(一個由window.TestJS = new TestJS()分配)。該屬性不會被任何其他對象繼承。

當:

console.log(new TestJS().data.val_name_1); 

運行,由new TestJS()返回的對象一直沒有它的叫又initData方法,因此它不具有數據財產,並沒有繼承它從構造函數(因爲屬性直接在構造函數本身上,而不是它的原型)。

還要注意的是分配一個新的對象來this.data創建直接在實例屬性,因此增加this.data被修改實例的數據對象,而不是在構造函數的原型之一。

代碼中的模式(尤其是第二個模式)似乎不必要的複雜。

+0

我不認爲OP的問題是。它似乎只是爲了調試目的而添加的。緊接着的一行是檢查'TestJS.data'並且仍然返回undefined。我認爲這是一個範圍界定問題。 –

+0

也許,我看不到OP發佈的圖像。這個問題構思不佳,因爲它沒有說明首先會有什麼。也許是時候關閉了。 – RobG

0

它與IIFE的範圍有關。在閉包內聲明的變量會隱藏任何具有相同名稱的外部變量。由於IIFE執行後不再有權訪問它的作用域,它內部的TempJS將始終是一個函數構造函數 - 不是實例化的對象。

考慮這個例子:

var i; 
var func = (function(){ 
    i = 1; 
    return function() { 
     console.log(i) 
    }; 
})(); 

func(i); // 1 

i = 2; 
func(i); // 2 

如果我重新申報瓶蓋內的i變量,看看會發生什麼:

var i = 1; 
var func = (function(){ 
    var i = 1; 
    return function() { 
     console.log(i) 
    }; 
})(); 

func(i); // 1 

i = 2; 
func(i); // 1 

所以一個解決問題的方法是申報TestJS一次在IIFE之前。

var TestJS; 

(function(w){ 
    if(!w) 
    return; 

    TestJS = function(){ 
    }; 

// ... 

    TestChildJS:{ 
     initChild:function(){ 
     console.log(TestJS.data.val_name_1); 
     } 
// ... 

    window.TestJS = new TestJS(); 
})(window); 

TestJS.initData(); 
console.log(TestJS.TestChildJS.initChild()); // 1 

請注意,我刪除了console.log(new TestJS().data.val_name_1);TestJS不再是一個構造函數,所以該行會拋出。

另一種解決方法是在閉包內部將空函數表達式分配給window.TestJS,而不是var TestJS。這樣做不會創建名稱的本地TestJS,因此將防止含糊不清。

+1

請注意,* window *被傳遞給* w *,所以不妨使用它(因爲它是毫無意義的)。 'TestJS = function ...'應該是'w.TestJS = function ...'或'window.TestJS = new TestJS()'應該是'TestJS = new TestJS()'。即在任何地方使用* window * *的* w *別名或根本不使用* w *別名。 – RobG

+0

@RobG Yup,同意。 –