2015-01-21 157 views
3

我一直在研究有關「私有」變量繼承多個leveles在JavaScript中每一個「類」,但碰上這種奇特的奇點:的Javascript原型繼承私有方法

function Ammo() { 
    var a = 0; 
    this.get_ammo = function() { 
     return a; 
    }; 

    this.add_to_ammo = function() { 
     a = a+1 
     return a; 
    }; 

    this.clean_ammo = function() { 
     return a=0; 
    } 
} 

function Weapon() { 
    var a =0; 
} 

function Gun() { 
    var a = 0; 
    this.fire = function(){ 
     console.log("Bang"); 
    } 
} 

Weapon.prototype = new Ammo(); 
Weapon.prototype.constructor = Weapon(); 

Gun.prototype = new Weapon(); 
Gun.prototype.constructor = Gun(); 

var a = new Ammo(); 
var w = new Weapon(); 
var g = new Gun(); 

a.add_to_ammo() 
a.add_to_ammo() 
a.add_to_ammo() 
console.log(w.get_ammo()) 
// At this point I get 0, as expected. But after 
w.add_to_ammo() 
w.add_to_ammo() 
w.add_to_ammo() 
console.log(g.get_ammo()) 
// But here I get 3! 

有人可以解釋爲什麼我送3後

console.log(g.get_ammo()) 

我認爲物體A,W,G是獨立的,所以他們的領域。

而且我發現,如果我改變

var a = 0; 

this.a = 0; 

我得到預期的結果。對象的領域與他們的父母領域沒有任何聯繫。

回答

4

var a定義在Ammo中,但在其他構造函數中var a完全沒有。當您調用該方法時,無論哪個實例總是與在Ammo中的閉包中捕獲的相同a一樣,您正在修改的是a

你不能在JavaScript中使用像你想要的私有變量,這沒關係。要做到這一點,最常用的方法是把這些變量公衆,並用下劃線前綴,將它標記爲「內部」:

function Ammo() { 
    this._ammo = 0; 
} 

然後將方法添加到prototype和使用this._ammo引用變量:

Ammo.prototype.getAmmo = function() { 
    return this._ammo 
} 

然後你就可以用Object.create繼承:

Weapon.prototype = Object.create(Ammo.prototype); 

並在構造函數 「調用super」:

function Weapon() { 
    Ammo.call(this) // gets own "_ammo" 
} 

此外,您沒有正確設置構造函數。你應該分配一個函數,而不是稱之爲:

Weapon.prototype.constructor = Weapon; 
Gun.prototype.constructor = Gun; 
0

我沒有足夠的代表點評論@elclanrs答案,所以原諒我。

他的答案是正確的,但最相關的資料片是最後

而且,你是不是正確設置的構造函數。你應該分配的功能,而不是把它叫做:

Weapon.prototype.constructor = Weapon; 
Gun.prototype.constructor = Gun; 

您的變量是函數閉包的範圍內聲明的其實都是保密的!然而,你從來沒有正確地實例化你的子類對象,所以你有一個frankenstein事情發生:一個對象,很多身體部位。

除此之外,你的代碼沒有什麼內在的錯誤,它只是不是人們通常寫的「類」的方式,我不會解釋爲什麼在這個問題的上下文中。