2012-02-28 9 views
7

मैं पाइथन और स्मॉलटॉक में पृष्ठभूमि से जावास्क्रिप्ट में आ रहा हूं, और मैं भाषा में स्वयं और लिस्प के लिनेज की सराहना करता हूं। ईसीएमएस्क्रिप्ट 5 के साथ, मैं नए ऑपरेटर के बिना प्रोटोटाइप ओओ में अपना हाथ देखना चाहता था।ऑब्जेक्ट.क्रेट और नामित रचनाकारों के साथ प्रोटोटाइप ओओ

प्रतिबंध:

  • वैकल्पिक नए ऑपरेटर कक्षाएं बनाने के लिए
  • प्रोटोटाइप श्रृंखला समर्थन डिबगिंग
  • alloc() init() निर्माण की तरह अनुक्रम WebInspector के लिए instanceof
  • नामित निर्माताओं के लिए सही होनी चाहिए। उद्देश्य-सी और पायथन

टी को पूरा करने के कार्यान्वयन पर मेरा प्रयास यहां है वह मापदंड:

function subclass(Class, Base) { 
    "use strict"; 
    function create(self, args) { 
     if (!(self instanceof this)) 
      self = Object.create(this.prototype); 
     var init = self.__init__; 
     return init ? init.apply(self, args) : self; 
    } 
    if (Base instanceof Function) Base = Base.prototype; 
    else if (Base===undefined) Base = Object.prototype; 

    Class.prototype = Object.create(Base); 
    Class.prototype.constructor = Class; 
    Class.create = create; 

    Class.define = function define(name, fn) { return Class.prototype[name] = fn; }; 
    Class.define('__name__', Class.name); 
    return Class; 
} 

और यह एक सरल mockup में काम करने के लिए लगता है:

function Family(){return Family.create(this, arguments)} 
subclass(Family, Object); 
Family.define('__init__', function __init__(n){this.name=n; return this;}); 

function Tribe(){return Tribe.create(this, arguments)} 
subclass(Tribe, Family); 
function Genus(){return Genus.create(this, arguments)} 
subclass(Genus, Tribe); 
function Species(){return Species.create(this, arguments)} 
subclass(Species, Genus); 

एक कारखाने समारोह के रूप में वर्ग का उपयोग करना:

var dog = Species('dog'); 
console.assert(dog instanceof Object); 
console.assert(dog instanceof Family); 
console.assert(dog instanceof Tribe); 
console.assert(dog instanceof Genus); 
console.assert(dog instanceof Species); 

या नए ऑपरेटर का उपयोग:

var cat = new Species('cat'); 
console.assert(cat instanceof Object); 
console.assert(cat instanceof Family); 
console.assert(cat instanceof Tribe); 
console.assert(cat instanceof Genus); 
console.assert(cat instanceof Species); 

console.assert(Object.getPrototypeOf(dog) === Object.getPrototypeOf(cat)) 

क्या मैंने जरूरी अनदेखा किया है मेरे कार्यान्वयन में प्रोटोटाइप ओओ की विशेषताएं? क्या जावास्क्रिप्ट सम्मेलन या इंटरैक्शन हैं जिसके लिए मुझे बदलाव करना चाहिए? संक्षेप में, यहां "गॉचा" क्या हैं, और क्या कोई स्पष्ट सुधार किया जा सकता है?

मैं निर्माता की परिभाषाओं के साथ DRYER बनना चाहता था, लेकिन मैंने पाया कि एक फ़ंक्शन का नाम संपत्ति लिखने योग्य नहीं है, और यही वेबकिट इंस्पेक्टर के ऑब्जेक्ट नामों का समर्थन करता है। मैं जो चाहता था उसे पूरा करने के लिए एक eval निर्माण करने में सक्षम था, लेकिन ... यक।

+0

वाह, मैं कभी नहीं जावास्क्रिप्ट इस तरह का उपयोग कर देखा है ... अगर जब तुम पर कार्रवाई "अविश्वसनीय" datas –

+0

eval खतरनाक है, लेकिन मुझे नहीं क्यों एक eval उपयोग नहीं करना चाहिए, वास्तव में जब आप ऐसा करते हैं [ अस्थिर] आप किसी प्रकार के eval का उपयोग कर रहे हैं, क्योंकि जेएस में कोई सहयोगी सरणी नहीं हैं। – mpm

+1

@camus yes, और मैंने यह सुनिश्चित करने के लिए एक '/ \ w +/'regexp भी उपयोग किया है कि यह केवल एक वैध विधि नाम था। लेकिन ऐसा लगता है कि एक स्टेक स्थापित करने के लिए स्लेजहैमर का उपयोग करना - यह फ़ंक्शन की नाम संपत्ति सेट करने की अनुमति देने पर बहुत अधिक सुरुचिपूर्ण होगा। जावास्क्रिप्ट एक प्रोटोटाइप भाषा है, सभी के बाद ... –

उत्तर

8

संपादित करें: ओह, अब मैं सवाल देखता हूं। उत्तर: नहीं, आपको यह बिल्कुल सही मिला। फ़ंक्शन का नाम सेट करने का एकमात्र तरीका फ़ंक्शन घोषणाओं का उपयोग करते समय होता है, जिसका मतलब मूल्यांकन समय पर होता है। इस प्रकार आपको इसे स्रोत कोड में रखना होगा (जो पीछे का दरवाजा है)। मैंने पहले एक सरल सवाल का जवाब दिया लेकिन एक ही जिस्ट के साथ: Minor drawback with Crockford Prototypical Inheritance। इस विषय पर एक अन्य संसाधन http://kangax.github.com/nfe/

displayName संपत्ति का उपयोग करने के लिए आंदोलन है ताकि इसे डीबगर उपस्थिति से किसी फ़ंक्शन का अपरिवर्तनीय नाम तलाक दिया जा सके। यह फ़ायरफ़ॉक्स और कुछ अन्य सामानों में लागू किया गया है, और एएस 6 में शामिल करने के लिए एक स्ट्रॉमैन है लेकिन अभी तक टेंटेटिव स्पेक का हिस्सा नहीं है: http://wiki.ecmascript.org/doku.php?id=strawman:name_property_of_functions

नामकरण कार्यों के विषय में क्रोम पर काम करने वाले कुछ लोगों का एक पेपर यहां दिया गया है http://code.google.com/p/chromium/issues/detail?id=17356

मूल जवाब रैंप:

आप बाहर सेट क्या पूरा करने के लिए, आप इसे अच्छी तरह से किया है http://querypoint-debugging.googlecode.com/files/NamingJSFunctions.pdf

और यहाँ पर चर्चा क्यों यह अभी तक लागू नहीं है क्रोमियम मुद्दा है।इसी प्रकार सामान के कुछ उदाहरण मेरे द्वारा की गई: (

var MyObjCtor = heritable({ 
    constructor: function MyObj(){ /* ctor stuff */}, 
    super: SomeCtor, 
    prop1: val, 
    prop2: val, 
    /**etc..*/ 
}); 


function heritable(definition){ 
    var ctor = definition.constructor; 
    Object.defineProperty(ctor, 'super', { 
    value: definition.super, 
    configurable: true, 
    writable: true 
    }); 
    ctor.prototype = Object.create(ctor.super.prototype); 
    delete definition.super; 

    Object.keys(definition).forEach(function(prop){ 
    var desc = Object.getOwnPropertyDescriptor(definition, prop); 
    desc.enumerable = false; 
    Object.defineProperty(ctor.prototype, prop, desc); 
    }); 

    function construct(){ 
    var obj = new (ctor.bind.apply(ctor, [].concat.apply([null], arguments))); 
    ctor.super.call(obj); 
    return obj; 
    } 

    construct.prototype = ctor.prototype; 

    return construct; 
} 

अन्य libffi साथ प्रयोग के लिए structs बनाने में है:

पहले एक सरल 'पैतृक' समारोह है जो आप की तरह सामान करने की अनुमति देता है नोड ffi)। अनिवार्य रूप से यहां आपके पास कन्स्ट्रक्टर विरासत और प्रोटोटाइप विरासत दोनों हैं। आप ऐसे रचनाकार बनाते हैं जो रचनाकारों से प्राप्त होते हैं, जो structs के उदाहरण बनाते हैं। https://github.com/Benvie/node-ffi-tools/blob/master/lib/Struct.js

नामित फ़ंक्शन बनाने के लिए eval का उपयोग आवश्यक है, इसलिए यह है कि यदि आपको नामित निर्माता की आवश्यकता है। जहां आवश्यक हो वहां इसका उपयोग करने के बारे में मेरे पास कोई योग्यता नहीं है।

+0

लिंक संयुक्त, कोड नमूने, और कोड समीक्षा बेहद सहायक हैं - धन्यवाद। अंतर्दृष्टि के लिए –

4

शेन मैं अपनी पृष्ठभूमि जावास्क्रिप्ट से आ रही आप बता सकते हैं तुम क्या करने कोशिश कर रहे हैं की तुलना में एक अलग ढंग से व्यवहार करता है। इससे पहले कि आप तुरंत नफरत है कि इस सवाल का जवाब पर पढ़ें ...

मैं OOP प्यार और एक बहुत ही OOP अनुकूल पृष्ठभूमि से आते हैं। प्रोटोटाइप ऑब्जेक्ट्स के आसपास मेरे सिर को लपेटने में मुझे कुछ समय लग रहा है (प्रोटोटाइप विधियों को स्थिर कार्य के रूप में सोचें ... जो केवल प्रारंभिक वस्तुओं पर काम करते हैं)। जावास्क्रिप्ट में किए गए कई चीजें ऐसी भाषा से बहुत "गलत" आती हैं जो अच्छी सुरक्षा और encapsulation का उपयोग करती है।

'नई' ऑपरेटर का उपयोग करने के लिए केवल वास्तविक कारण यदि आप एक से अधिक इंस्टेंस बनाने या जब तक एक घटना शुरू हो रहा है चलने से तर्क के कुछ प्रकार को रोकने के लिए कोशिश कर रहे हैं।

मैं जानता हूँ कि यह एक जवाब नहीं है ... यह था अभी भी टिप्पणी में टाइप करने के लिए ज्यादा। वास्तव में एक बेहतर परिप्रेक्ष्य प्राप्त करने के लिए आपको ऑब्जेक्ट और वर्र्स बनाना चाहिए और अपना डोम देखना चाहिए ... आपको पता चलेगा कि आप इसके कारण किसी भी संदर्भ से सचमुच कहीं भी प्राप्त कर सकते हैं। मुझे विवरण भरने के लिए these articles बहुत संसाधन मिला।

शुभकामनाएं।

अद्यतन

तो अगर आप एक ही वस्तु के विभिन्न उदाहरणों बनाने के लिए यहां कुछ सुझाव दिए गए काश मैंने सुना है चाहते हैं एक कारखाने विधि की आवश्यकता है:

  • कृपया कृपया कृपया,, ओओ encapsulation से पता चला है कि आप सभी नियमों के बारे में भूल जाओ। मैं इस वजह से कहते हैं कि जब आपके आद्य वस्तुओं शाब्दिक वस्तुओं का उपयोग कर, और उदाहरण के साथ वस्तुओं वहाँ एक रास्ता है कि आप करने के लिए प्राकृतिक नहीं होगा में चीजों का उपयोग करने के कई मायनों हो जाएगा।
  • यदि आप किसी भी प्रकार के अबास्ट्रक्शन या विरासत का उपयोग करने की योजना बनाते हैं तो मैं अत्यधिक डीओएम के साथ खेलने का सुझाव दूंगा। कुछ ऑब्जेक्ट बनाएं और उन्हें डोम में देखें और देखें कि क्या हो रहा है। आप मौजूदा प्रोटोटाइप का उपयोग करके अपनी विरासत का अनुकरण कर सकते हैं (इसने मुझे इंटरफेस और अमूर्त वर्गों का विस्तार करने के लिए मार डाला नहीं है!)।
  • पता है कि जावास्क्रिप्ट में सब कुछ एक वस्तु है ... यह आपको कुछ बहुत अच्छी चीजें करने के लिए अनुमति देता है (चारों ओर फ़ंक्शन पास करता है, फ़ंक्शन लौटाता है, आसान कॉलबैक विधियां बनाता है)। जावास्क्रिप्ट कॉल '.call()', '.apply()', और '.bind()' देखें।

इन 2 चीजों को जानना आपके समाधान को हल करने में आपकी मदद करता है। अपने डोम को साफ रखने और अच्छे जावास्क्रिप्ट विकास अभ्यास का पालन करने के लिए आप वैश्विक नामस्थान को साफ रखें (डीओएम में विंडो संदर्भ)। यह आपको जो कुछ भी कर रहा है उसके बारे में आपको "गलत" महसूस करने के बारे में "बेहतर" महसूस करेगा। और सुसंगत रहें।

ये बातें मैं परीक्षण और त्रुटि से सीखा है।जावास्क्रिप्ट एक महान और अनूठी भाषा है यदि आप अपने सिर को क्लासिक ओओ भाषाओं से अपने अंतर के चारों ओर लपेट सकते हैं। शुभ लाभ!

+0

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

+1

@ShaneHolloway ठीक है, ठीक है। फिर आपको अपनी वस्तुओं को बनाने के लिए 'नया' कीवर्ड का उपयोग करना चाहिए। मैं यह देखने के लिए अपना उत्तर अपडेट करूंगा कि यह आपकी मदद करता है या नहीं। – jjNford

+0

महान अनुभव और सुझावों के लिए धन्यवाद। मैं मानता हूं कि प्रोटोटाइप प्रोग्रामिंग शुरू करने के लिए एक छोटा दिमाग है। –

1

आप नाम के बिना नामित रचनाकार नहीं बना सकते हैं। लाइब्रेरी नामस्थानों को लागू करने पर नाम के साथ एक छिपी हुई संपत्ति वाला एक कन्स्ट्रक्टर होगा।

शेष प्रश्न का उत्तर देते हुए, बहुत सारे जावास्क्रिप्ट क्लास पुस्तकालय हैं। यदि आप इसे सही तरीके से करना चाहते हैं तो आप अपना खुद का लिख ​​सकते हैं लेकिन एक सही विरासत प्रणाली को समझने और लागू करने के लिए थोड़ा गन्दा है।

मैंने हाल ही में अपनी पुस्तकालयों को सभी पुस्तकालयों में सुधार करने की कोशिश की है: Classful JS। मुझे लगता है कि यह देखने के लायक है क्योंकि इसका सरल डिज़ाइन, उपयोग, और कुछ अन्य सुधार जैसे सबक्लास से किसी भी सुपर विधि को कॉल करना (मैंने ऐसा कोई लाइब्रेरी नहीं देखा है जो ऐसा कर सकता है, वे सभी केवल सुपर विधि को कॉल कर सकते हैं अधिभावी)।

3

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

// ------- Base Animal class ----------------------- 
var Animal = function(name) { 
    this.name = name; 
}; 

Animal.prototype.GetName = function() { 
    return this.name; 
}; 
// ------- End Base Animal class ----------------------- 

// ------- Inherited Dog class ----------------------- 
var Dog = function(name, breed) { 
    Animal.call(this, name); 
    this.breed = breed; 
}; 

Dog.prototype = new Animal(); 
Dog.prototype.constructor = Dog; 

Dog.prototype.GetBreed = function() { 
    return this.breed; 
}; 

Dog.prototype.Bark = function() { 
    alert(this.GetName() + ' the ' + this.GetBreed() + ' says "Arf!"'); 
}; 
// ------- End Inherited Dog class ----------------------- 

// Usage 
var harper = new Dog('Harper', 'miniature pinscher'); 
harper.Bark(); 
+1

मुझे एक उदाहरण शुरू करने के लिए '.call' के इस उपयोग को पसंद है, यह बहुत साफ है लेकिन आप अपरकेस अक्षर से शुरू होने वाले विधि नामों का उपयोग क्यों करते हैं - जावास्क्रिप्ट में नामकरण सम्मेलनों के अनुसार सभी नामों को कन्स्ट्रक्टर नामों को छोड़कर लोअरकेस अक्षर से शुरू होना चाहिए और कुछ होस्ट ऑब्जेक्ट नाम – Luc125

+1

मुझे नामकरण सम्मेलनों को पसंद नहीं आया है जहां मैंने देखा है कि लगभग सबकुछ ऊंट है। मैं पस्कलकेस को "कक्षाएं" और "सार्वजनिक विधियों" और ऊंट को पठनीयता के साथ सहायता करने के लिए सबकुछ बना देता हूं। – JoshNaro

+0

मैंने इस जावास्क्रिप्ट ओओपी मुहावरे को कई जगहों पर देखा है - यह अनिवार्य रूप से क्रॉकफोर्ड का स्यूडोक्लैसिकल उदाहरण है जो उसके सहायक तरीकों के बिना है। दुर्भाग्यवश, मेरे उपयोग के मामले में "वर्ग" दोनों कारखाने के तरीकों के साथ-साथ मानक जावास्क्रिप्ट कन्स्ट्रक्टर के रूप में सही ढंग से काम करने की आवश्यकता है। –

संबंधित मुद्दे