2009-07-25 15 views
8

क्या इस पैटर्न के साथ जावास्क्रिप्ट "कक्षा" का उपयोग करने के लिए कोई डाउनसाइड्स हैं?जावास्क्रिप्ट "कक्षाएं"

var FooClass = function() 
{ 
    var private = "a private variable"; 
    this.public = "a public variable"; 

    var privatefn = function() { ... }; 
    this.publicfn = function() { ... }; 
}; 

var foo = new FooClass(); 
foo.public = "bar"; 
foo.publicfn(); 

उत्तर

14

आप अपने उदाहरण में क्या कर रहे हैं वह "वर्ग" पैटर्न नहीं है जो लोग जेएस में सोचते हैं - आमतौर पर लोग जावा/सी #/सी ++/आदि के "सामान्य" वर्ग मॉडल के बारे में सोच रहे हैं जो हो सकता है पुस्तकालयों के साथ faked।

इसके बजाय अपने उदाहरण वास्तव में काफी सामान्य है और अच्छी जे एस डिजाइन है, लेकिन पूर्णता के लिए मैं व्यवहार मतभेद पर चर्चा करेंगे आप निजी और सार्वजनिक "सदस्यों" के बीच देखेंगे आप

var private = "a private variable"; 
this.public = "a public variable"; 

के भीतर से private तक पहुँचना है public तक पहुंचने से आपके कोई भी कार्य काफी तेज होगा क्योंकि private का स्थान जेएस इंजन द्वारा स्थिर लुकअप के साथ उचित रूप से ठीक से निर्धारित किया जा सकता है। public तक पहुंचने के प्रयासों को एक लुकअप की आवश्यकता होती है, अधिकांश आधुनिक जेएस इंजन लुकअप कैशिंग की डिग्री करते हैं, लेकिन यह अभी भी एक सरल स्कॉप्ड वैर एक्सेस से अधिक महंगा है।

var privatefn = function() { ... }; 
this.publicfn = function() { ... }; 

ही देखने के नियमों के साथ ऊपर चर तक पहुँचता है के रूप में इन कार्यों के लिए लागू होते हैं, केवल वास्तविक अंतर (अपने उदाहरण में) है कि अपने कार्यों कहा जाता है कर रहे हैं, कहते हैं कि privatefn() बनाम this.publicfn(), privatefn हमेशा वैश्विक मिल जाएगा है this के लिए ऑब्जेक्ट। लेकिन यह भी अगर कोई करता है

f = foo.publicfn; 
f(); 

फिर f करने के लिए कॉल thisलेकिन के रूप में वैश्विक वस्तु यह private चर को संशोधित करने में सक्षम हो जाएगा होगा।

हालांकि सार्वजनिक कार्यों को करने का अधिक सामान्य तरीका (जो निजी सदस्यों के मुद्दे को संशोधित करने वाले अलग-अलग सार्वजनिक कार्य को हल करता है) प्रोटोटाइप पर सार्वजनिक कार्यों को रखना है, उदाहरण के लिए।

Foo.prototype.publicfn = function() { ... } 

कौन सा सार्वजनिक कार्यों बलों निजी जानकारी को संशोधित नहीं करने के लिए - वहाँ कुछ समय जहां यह एक विकल्प नहीं है, लेकिन यह अच्छी आदत है के रूप में यह भी थोड़ा स्मृति उपयोग कम कर देता है, ले:

function Foo1() { 
    this.f = function(){ return "foo" }; 
} 

बनाम
function Foo2() { 
} 
Foo2.prototype.f = function(){ return "foo" }; 

Foo1 में आप (Foo1 के प्रत्येक उदाहरण नहीं सभी एमोरी के लिए समारोह वस्तु की एक प्रति है, बस वस्तु, जैसे। new Foo1().f !== new Foo2().f) जबकि Foo2 में केवल एक ही कार्य वस्तु है।

3

यह अब तक अच्छा है, लेकिन आपके पास छोड़ दिया गया एक और पहुंच स्तर है।

this.publicfn वास्तव में एक प्रबल विधि है क्योंकि इसमें निजी सदस्यों और कार्यों तक पहुंच है।

तरीकों जो सार्वजनिक लेकिन priveleged नहीं हैं जोड़ने के लिए, इस प्रकार प्रोटोटाइप को संशोधित:

FooClass.prototype.reallypublicfn = function() { ... }; 

टिप्पणी है कि इस विधि FooClass के निजी सदस्यों के लिए पहुँच नहीं है, लेकिन यह FooClass के किसी भी मामले के माध्यम से पहुँचा जा सकता है।

इस को पूरा करने का एक और तरीका निर्माता

var FooClass = function() 
{ 
    var private = "a private variable"; 
    this.public = "a public variable"; 

    var privatefn = function() { ... }; 
    this.publicfn = function() { ... }; 

    return { 
    reallypublicfn: function() { ...} 
    } 
}; 

var foo = new FooClass(); 
foo.public = "bar"; 
foo.publicfn(); 

मूल रूप से इन तरीकों लौटा रहा है, डेटा के इन तरीकों आप पारंपरिक OOP तकनीक का पालन मदद छुपा। आम तौर पर, अपने वर्गों में डेटा-छिपाने और encapsulation में सुधार एक अच्छी बात है। कम युग्मन सुनिश्चित करना सड़क के नीचे चीजों को बदलने में बहुत आसान बनाता है, इसलिए जितना संभव हो सके सार्वजनिक रूप से उजागर करना वास्तव में आपके लाभ के लिए है।

इन चीजों को पूरा करने के तरीके के विवरण के लिए https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript एक साधारण अवलोकन और http://www.crockford.com/javascript/private.html देखें।

+1

आपका FooClass उदाहरण गलत है। नए के अर्थशास्त्र प्रभावी ढंग से हैं: "var foo = {}; foo .__ proto__ = FooClass.prototype; var temp = FooClass.call (temp); अगर (IsObject (temp)) foo = temp;"। इसका मतलब है कि आपके उदाहरण में foo नई वस्तु होगी "{reallypublicfn: function() {...}}" इसलिए इसमें FooClass प्रोटोटाइप या publicfn फ़ंक्शन – olliej

3

मुख्य नकारात्मक बात यह है कि आप FooClass के प्रत्येक उदाहरण के लिए publicfn की एक प्रति के साथ हवादार हो जाएंगे। आप FooClass वस्तुओं का एक बहुत कुछ बना रहे होते हैं, तो यह लिखने

FooClass.prototype.publicfn = function() { ... }; 
+1

ध्यान नहीं दिया जाएगा कि publicfn बनाने के उन दो तरीके समकक्ष नहीं हैं । एक priveleged है और दूसरा नहीं है –

1

यह अपनी आवश्यकताओं और रिश्तेदार प्रदर्शन पर निर्भर करता है के लिए और अधिक कुशल हो जाएगा। जावास्क्रिप्ट सबसे अधिक प्रकार की सुरक्षित भाषा नहीं है और सदस्य दृश्यता के संबंध में बहुत मजबूत नहीं है। परंपरागत रूप से आप जावास्क्रिप्ट प्रकार के भीतर "निजी", "सार्वजनिक विशेषाधिकार" और "सार्वजनिक" दृश्यता प्राप्त कर सकते हैं।

आप का उपयोग निजी और सार्वजनिक विशेषाधिकार प्राप्त सदस्यों की घोषणा कर सकते हैं:

function FooClass() 
{ 
    var privateVar = 1; 
    function privateFn() 
    { 
     return privateVar; // etc... 
    } 
    this.publicVar = 2; 
    this.publicFn = function() 
    { 
     return privateFn(); 
    } 
} 

यह उदाहरण एक समारोह बंद, एक समारोह घोषणा कि गुंजाइश जहां समारोह परिभाषित किया गया है से मूल्यों को भी शामिल होते हैं जो उपयोग करता है। यह स्वीकार्य है जब सदस्य दृश्यता आवश्यक है लेकिन ओवरहेड का कारण बन सकती है। जावास्क्रिप्ट दुभाषिया प्रत्येक तत्कालता के लिए निजी एफएन या सार्वजनिक परिभाषाओं का पुन: उपयोग नहीं कर सकता क्योंकि वे बाहरी दायरे में चर या कार्यों का संदर्भ लेते हैं। नतीजतन FooClass के प्रत्येक उदाहरण के परिणामस्वरूप निजी एफएन और publicFn के लिए अतिरिक्त संग्रहण स्थान होता है। यदि प्रकार निरंतर या संयम में उपयोग किया जाता है तो प्रदर्शन जुर्माना अस्वीकार्य है। यदि पृष्ठ में अक्सर उपयोग किया जाता है, या यदि पृष्ठ "AJAX" शैली से अधिक है, जहां पृष्ठ को तब तक मुक्त नहीं किया जाता है जब पृष्ठ अनलोड नहीं किया जाता है तो जुर्माना अधिक दिखाई दे सकता है।

प्रोटोटाइप सदस्यों का उपयोग करने का एक वैकल्पिक दृष्टिकोण है। ये अप्रतिबंधित सार्वजनिक सदस्य हैं। चूंकि जावास्क्रिप्ट पूरी तरह से टाइप-सुरक्षित नहीं है और इसे लोड होने के बाद संशोधित करना अपेक्षाकृत आसान है, इसलिए सुरक्षा टाइप करें और सदस्य दृश्यता इंटीरियर टाइप करने के लिए उपयोग को नियंत्रित करने के लिए विश्वसनीय नहीं हैं। प्रदर्शन कारणों से, दृश्यता नियमों का अनुमान लगाने के लिए सदस्य नामकरण का उपयोग करके एएसपी.NET अजाक्स जैसे कुछ ढांचे। उदाहरण के लिए, ASP.NET अजाक्स में एक ही प्रकार लग सकता है जैसे: निजी दायरे वाले सदस्यों

function FooClass2() 
{ 
    this._privateVar = 1; 
    this.publicVar = 2; 
} 
FooClass2.prototype = 
{ 
    _privateFn : function() 
    { 
     return this._privateVar; 
    }, 
    publicFn : function() 
    { 
     return this._privateFn(); 
    } 
} 
FooClass2.registerClass("FooClass2"); 

इस मामले में नाम केवल, "_" उपसर्ग एक निजी सदस्य चर मतलब करने के लिए माना जाता है में निजी होते हैं। यह सदस्य को वास्तव में निजी होने से रोकने का नकारात्मक पक्ष है, लेकिन वस्तु के इन-मेमोरी पैचिंग की अनुमति देने के ऊपर। दूसरा मुख्य लाभ यह है कि सभी कार्यों को दुभाषिया और इंजन द्वारा एक बार बनाया जाता है और इस प्रकार के लिए बार-बार उपयोग किया जाता है। "यह" कीवर्ड तब प्रकार के उदाहरण को संदर्भित करता है भले ही फ़ंक्शन संदर्भ स्वयं समान है।

एक तरह से कार्रवाई में अंतर को देखने के लिए दोनों प्रकार के साथ इस प्रयास करने के लिए है

var fooA = new FooClass(), fooB = new FooClass(); 
alert(fooA.publicFn===fooB.publicFn); // false 

var foo2A = new FooClass2(), foo2B = new FooClass2(); 
alert(foo2A.publicFn===foo2B.publicFn); // true 
(यदि आप ASP.NET अजाक्स की जरूरत नहीं है, तो आप उस registerClass() कॉल FooClass2 में अंतिम पंक्ति अनदेखा कर सकते हैं)

तो यह प्रकार की सुरक्षा और सदस्य दृश्यता बनाम बनाम मामला है।प्रदर्शन और स्मृति में पैच करने की क्षमता

0

इसके अलावा, अगर मैं इसके लिए कुछ उपयोगी उल्लेख कर सकता हूं - prototype के साथ आप एक बाहरी दायरे से फ़ंक्शन को विस्तारित करने के लिए कोड में बाद में अतिरिक्त विधियां जोड़ सकते हैं। एक छोटे से लाभ के रूप में, सभी विधियों के साथ पूरे शरीर को हर बार प्रस्तुत नहीं किया जाएगा, इसलिए यह प्रदर्शन को संकलित करता है। यदि आपके पास पहले से ही फ़ंक्शन के अंदर सभी घोषित विधियां हैं, तो इसे थोड़ा सा समय देने में अधिक समय लगेगा। तो, मेरी सलाह, इन्हें बाद में लागू करें जब वे वर्तमान कोड में रिलीज़ हो जाएं।

उदाहरण:

// inside 
function fn(arg) { 
    this.val = arg; 
    fn.prototype.getVal =()=> { 
     console.log(this.val); 
    } 
} 
var func = new fn('value'); 
func.getVal(); 


// declare extern methods 
function fn2(arg) { 
    this.val = arg; 
} 
fn2.prototype.getVal =()=> { 
    console.log(this.val); 
} 
var func2 = new fn2('value'); 
func2.getVal(); 
संबंधित मुद्दे