2013-07-15 19 views
10

我正在使用閉包來創建具有私有和公共方法的對象。它看起來像這樣 -你能繼承JavaScript中的私有函數嗎?

var Dog = (function() { 
    function Dog() {} 

    var size = 'big'; 

    var _privateSaySize = function() { 
     return 'I am a ' + size + ' dog.'; 
    } 

    Dog.prototype.publicSaySize = function() { 
     return _privateSaySize(); 
    } 

    return Dog; 
})(); 

但現在我想有一個只有私有函數的對象,由另一個對象繼承。但這是可能的JavaScript?

+1

這是什麼功能狗=(函數(){})()'? – Amberlamps

+2

只有在_any_語言中定義了'private'成員才能支持OOP。我沒有得到你想要做的。 – Leri

+0

一般來說不,但是你的「私人功能」很容易通過'notSoPrivateSaySize = new Dog()來訪問。publicSaySize();' – Bergi

回答

1

你想讓一個實例繼承另一個實例的私有狀態嗎?當然你可以在JavaScript中做到這一點。首先,我們需要定義一個效用函數:

function weakBind(functable, prototype, state) { 
    return function() { 
     return functable.apply(this, Object.getPrototypeOf(this) === prototype ? 
      [state].concat(Array.prototype.slice.call(arguments)) : arguments); 
    }; 
} 

現在,我們可以創建基類如下:

var Dog = (function() { 
    function Dog() { 
     if (this instanceof Dog) { 
      // constructor code 
     } else return Object.create(private); 
    } 

    var public = Dog.prototype, private = Object.create(public, { 
     size: { 
      value: "big" 
     } 
    }); 

    public.saySize = weakBind(function (private) { 
     return "I am a " + private.size + " dog."; 
    }, public, private); 

    return Dog; 
}()); 

現在你可以創建一個狗如下:

var dog = new Dog; 
alert(dog.saySize()); // I am a big dog. 
alert(dog.size);  // undefined 

我們可以繼承私有狀態如下:

var Chihuahua = (function() { 
    function Chihuahua() { 
     Dog.call(this); 
    } 

    var private = Dog(); 

    Object.defineProperty(private, { 
     size: { 
      value: "small" 
     } 
    }); 

    var public = Chihuahua.prototype = Object.create(Dog.prototype); 

    public.saySize = weakBind(public.saySize, public, private); 

    return Chihuahua; 
}()); 
現在210

您可以創建一個奇瓦瓦如下:

var chi = new Chihuahua; 
alert(chi.saySize()); // I am a small dog. 
alert(chi.size);   // undefined 

觀看演示:http://jsfiddle.net/b3Eyn/

注:我寫這個答案只是爲了表明它可能在JavaScript中繼承私有狀態。不過,我會建議你不要使用這種模式。如果你設計好你的代碼,那麼你就不需要首先繼承私有狀態。

8

不,你不能。

JavaScript繼承是基於原型的,因此您只能在原型中「擴展」方法。

+0

同意。雖然值得注意的是,許多JS開發人員只是在公開的方法前加上下劃線來表明它們受到保護或者不屬於公共API。如果開發者願意,開發者可以選擇修改它們,但這是他們自己的風險。說實話,試圖在JS中獲得一個可公開訪問的對象是一種相當無益的嘗試,因爲任何使用你的庫的人都可以重寫任何公共功能,甚至可以爭奪共享對象/原型。 這似乎並不值得頭痛。 –

2

種類...... 正如Bergi所指出的那樣,訪問是由範圍定義的,所以如果你在父類的直接內部定義了繼承者,你可以大致得到你想要的。

var BarkingDog; 
var Dog = (function() { 
    function Dog() {} 

    var size = 'big'; 

    var _privateSaySize = function() { 
     return 'I am a ' + size + ' dog.'; 
    }; 

    Dog.prototype.publicSaySize = function() { 
     return _privateSaySize(); 
    }; 

    BarkingDog = (function() { 
     function BarkingDog() {} 

     var say = 'woof'; 

     BarkingDog.prototype = new Dog(); 

     BarkingDog.prototype.bark = function() { 
      return _privateSaySize() + ' ' + say; 
     }; 

     return BarkingDog; 

    })(); 

    return Dog; 
})(); 

var myDog = new BarkingDog(); 
console.log(myDog.bark()); 
console.log(myDog.publicSaySize()); 

不知道爲什麼你會想,雖然...:d在JavaScript

5

的變量(功能)的隱私是通過功能範圍進行。只有從封閉範圍導出纔可以從外部訪問它們,除此之外沒有其他辦法。

要創建一個對象的方法可以訪問私有函數,您只需將它放在同一個範圍內即可。對象是否是從其他對象繼承的對象是非常不相關的。

function Dog() {} 
function Dalmatian() {} 
Dalmation.prototype = Object.create(Dog.prototype); 
Dalmation.prototype.size = "big"; 
function Dackel() {} 
Dackel.prototype = Object.create(Dog.prototype); 
Dackel.prototype.size = "small"; 

(function() { 
    // private function 
    function say(s) { 
     console.log("I'm a "+s+" dog"); 
    } 
    // both accessible from the Dog and Dackel public methods 
    Dog.prototype.saySize = function() { 
     say(this.size || "normal"); 
    }; 
    Dackel.prototype.saySize = function() { 
     say(this.size + " but loud"); 
    }; 
})(); 
new Dog().saySize(); 
new Dalmatian().saySize(); 
new Dackel().saySize(); 
0

您可以避免使用點符號。但它不是真正的私人。

var Dog = (function() { 
    function Dog() {} 

    var size = 'big'; 

    Dog.prototype['-privateSaySize'] = function() { 
     return 'I am a ' + size + ' dog.'; 
    } 

    Dog.prototype.publicSaySize = function() { 
     return this['-privateSaySize'](); 
    } 

    return Dog; 
})() 
+0

爲了表示屬性的「內部性」,下劃線'_'不是減號。這樣,你可以避免使用括號表示法...... – Bergi

+0

@Bergi這就是要點。我使用了一個減號,因爲這樣你不能使用點符號,所以它只能使用括號表示。 – boskop

+0

那有什麼幫助? [約定是使用下劃線](http://stackoverflow.com/q/4484424/1048572)來表示隱私。括號符號不會改變任何內容。 – Bergi