2010-03-14 20 views
12

डगलस क्रॉकफ़ोर्ड में जावास्क्रिप्ट: अच्छे भाग वह अनुशंसा करता है कि हम कार्यात्मक विरासत का उपयोग करें। यहाँ एक उदाहरण है:प्रोटोटाइप के साथ जावास्क्रिप्ट कार्यात्मक विरासत

var mammal = function(spec, my) { 
    var that = {}; 
    my = my || {}; 

    // Protected 
    my.clearThroat = function() { 
     return "Ahem"; 
    }; 

    that.getName = function() { 
     return spec.name; 
    }; 

    that.says = function() { 
     return my.clearThroat() + ' ' + spec.saying || ''; 
    }; 

    return that; 
}; 

var cat = function(spec, my) { 
    var that = {}; 
    my = my || {}; 

    spec.saying = spec.saying || 'meow'; 
    that = mammal(spec, my); 

    that.purr = function() { 
     return my.clearThroat() + " purr"; 
    }; 

    that.getName = function() { 
     return that.says() + ' ' + spec.name + ' ' + that.says(); 
    }; 

    return that; 
}; 

var kitty = cat({name: "Fluffy"}); 

मुख्य मुद्दा मैं इस के साथ किया है कि हर बार जब मैं एक mammal या cat जावास्क्रिप्ट दुभाषिया उस में सभी कार्यों को फिर से संकलित करने के लिए है बनाते हैं। यही है, आप उदाहरणों के बीच कोड साझा नहीं करते हैं।

मेरा सवाल है: मैं इस कोड को और अधिक कुशल कैसे बना सकता हूं? उदाहरण के लिए, यदि मैं हजारों cat ऑब्जेक्ट्स बना रहा था, तो prototype ऑब्जेक्ट का लाभ उठाने के लिए इस पैटर्न को संशोधित करने का सबसे अच्छा तरीका क्या है?

+0

"* इसमें सभी कार्यों को फिर से संकलित करना होगा। यही है, आपको उदाहरणों के बीच कोड साझा नहीं करना है "- नहीं। कोड साझा किया गया है, अलग-अलग स्कोप मानों के साथ केवल अलग-अलग फ़ंक्शन ऑब्जेक्ट्स बनाने की आवश्यकता है। यह एक विशाल ओवरहेड नहीं है। – Bergi

उत्तर

8

ठीक है, अगर आप mammal या cat के बहुत सारे बनाने की योजना बना रहे हैं तो आप बस ऐसा नहीं कर सकते हैं। इसके बजाय इसे पुराने तरीके से (प्रोटोटाइप) करें और संपत्ति के वारिस करें। आप अभी भी कन्स्ट्रक्टर के ऊपर जिस तरह से ऊपर हैं, लेकिन that और my के बजाय आप अंतर्निहित this और बेस क्लास का प्रतिनिधित्व करने वाले कुछ चर (इस उदाहरण में, this.mammal) का उपयोग कर सकते हैं।

cat.prototype.purr = function() { return this.mammal.clearThroat() + "purr"; } 

मैं आधार पहुँच के लिए my से एक और नाम का उपयोग करें और cat निर्माता में this में संग्रहीत चाहते हैं। इस उदाहरण में मैंने mammal का उपयोग किया था, लेकिन यदि आप स्थिर वैश्विक mammal ऑब्जेक्ट तक पहुंच प्राप्त करना चाहते हैं तो यह सबसे अच्छा नहीं हो सकता है। एक अन्य विकल्प वैरिएबल base नाम देना है।

+0

लिंक जोड़ने में समस्या 'my.mammal' के माध्यम से 'my' ऑब्जेक्ट यह है कि मैं इसके बारे में गोपनीयता खो दूंगा, क्योंकि कोई सिर्फ' cat.mammal.clearThroat() 'कर सकता है और संरक्षित विधि तक पहुंच सकता है। – cdmckay

+2

तो सच है। अगर आप गोपनीयता चाहते हैं तो आपको इसे सम्मेलन द्वारा करने की ज़रूरत है, उदाहरण के लिए, अंडरस्कोर के साथ अपने संरक्षित तरीकों से पहले। यदि यह बहुत ढीला लगता है, तो इस पर विचार करें कि यह "कार्यात्मक विरासत" पैटर्न भी एक सम्मेलन है। जावास्क्रिप्ट एक "साफ सनकी" भाषा नहीं है, यह है बहुत अधिक "मोटा और तैयार"। यह काम करने के लिए साफ-सुथरा तरीके से प्रदर्शन में जुर्माना लगाता है, जैसा कि आपको पता चला है। हालांकि, दंड का अधिक से अधिक मत बनो - इसमें हजारों ऑब्जेक्ट क्रिएशंस को काफी प्रभाव पड़ता है आपकी कुल गति की गति, आपके ई को दिया गया XAMPLE। – Plynx

+2

"कोई सिर्फ 'cat.mammal.clearThroat()' कर सकता है और संरक्षित विधि तक पहुंच सकता है "- कोड के साथ हर समस्या को हल करने की आवश्यकता नहीं है। सबसे बड़ा संभव सम्मान के साथ, आप विंडोज़ नहीं लिख रहे हैं। अगर कोई आपके कोड का दुरुपयोग करता है, तो यह कमाल है, क्योंकि इसका मतलब है कि कोई वास्तव में आपके कोड का उपयोग कर रहा है। कल्पित समस्याओं के खिलाफ सुरक्षा के बजाए उपयोगी, और सही ढंग से उपयोग करने में आसान कोड बनाने पर ध्यान केंद्रित करना बेहतर होगा। –

0

आप गोपनीयता चाहते हैं और आप protyping आप कर सकते हैं या इस दृष्टिकोण सकता है-नहीं चाहते पसंद नहीं करता है, तो:

(ध्यान दें .: यह jQuery.extend का उपयोग करता है)

var namespace = namespace || {}; 

// virtual base class 
namespace.base = function (sub, undefined) { 

    var base = { instance: this }; 

    base.hierarchy = []; 

    base.fn = { 

     // check to see if base is of a certain class (must be delegated) 
     is: function (constr) { 

      return (this.hierarchy[this.hierarchy.length - 1] === constr); 
     }, 

     // check to see if base extends a certain class (must be delegated) 
     inherits: function (constr) { 

      for (var i = 0; i < this.hierarchy.length; i++) { 

       if (this.hierarchy[i] == constr) return true; 
      } 
      return false; 
     }, 

     // extend a base (must be delegated) 
     extend: function (sub) { 

      this.hierarchy.push(sub.instance.constructor); 

      return $.extend(true, this, sub); 
     }, 

     // delegate a function to a certain context 
     delegate: function (context, fn) { 

      return function() { return fn.apply(context, arguments); } 
     }, 

     // delegate a collection of functions to a certain context 
     delegates: function (context, obj) { 

      var delegates = {}; 

      for (var fn in obj) { 

       delegates[fn] = base.fn.delegate(context, obj[fn]); 
      } 

      return delegates; 
     } 
    }; 

    base.public = { 
     is: base.fn.is, 
     inherits: base.fn.inherits 
    }; 

    // extend a sub-base 
    base.extend = base.fn.delegate(base, base.fn.extend); 

    return base.extend(sub); 
}; 

namespace.MyClass = function (params) { 

    var base = { instance: this }; 

    base.vars = { 
     myVar: "sometext" 
    } 

    base.fn = { 
     init: function() { 

      base.vars.myVar = params.myVar; 
     }, 

     alertMyVar: function() { 

      alert(base.vars.myVar); 
     } 

    }; 

    base.public = { 
     alertMyVar: base.fn.alertMyVar 
    }; 

    base = namespace.base(base); 

    base.fn.init(); 

    return base.fn.delegates(base,base.public); 
}; 

newMyClass = new namespace.MyClass({myVar: 'some text to alert'}); 
newMyClass.alertMyVar(); 

केवल नकारात्मक पक्ष यह है कि है, क्योंकि गोपनीयता दायरे के आप केवल वर्चुअल कक्षाओं का विस्तार कर सकते हैं, न कि आवर्तनीय वर्गों।

यहां एक उदाहरण है कि मैं कस्टमस्पेस.बेज कैसे बढ़ाता हूं, कस्टम ईवेंट को बाध्य/अनबाइंड/फायर करने के लिए।

// virtual base class for controls 
namespace.controls.base = function (sub) { 

    var base = { instance: this }; 

    base.keys = { 
     unknown: 0, 
     backspace: 8, 
     tab: 9, 
     enter: 13, 
     esc: 27, 
     arrowUp: 38, 
     arrowDown: 40, 
     f5: 116 
    } 

    base.fn = { 

     // bind/unbind custom events. (has to be called via delegate) 
     listeners: { 

      // bind custom event 
      bind: function (type, fn) { 

       if (fn != undefined) { 

        if (this.listeners[type] == undefined) { 
         throw (this.type + ': event type \'' + type + '\' is not supported'); 
        } 

        this.listeners[type].push(fn); 
       } 

       return this; 
      }, 

      // unbind custom event 
      unbind: function (type) { 

       if (this.listeners[type] == undefined) { 
        throw (this.type + ': event type \'' + type + '\' is not supported'); 
       } 

       this.listeners[type] = []; 

       return this; 
      }, 

      // fire a custom event 
      fire: function (type, e) { 

       if (this.listeners[type] == undefined) { 
        throw (this.type + ': event type \'' + type + '\' does not exist'); 
       } 

       for (var i = 0; i < this.listeners[type].length; i++) { 

        this.listeners[type][i](e); 
       } 

       if(e != undefined) e.stopPropagation(); 
      } 
     } 
    }; 

    base.public = { 
     bind: base.fn.listeners.bind, 
     unbind: base.fn.listeners.unbind 
    }; 

    base = new namespace.base(base); 

    base.fire = base.fn.delegate(base, base.fn.listeners.fire); 

    return base.extend(sub); 
}; 
1

मुझे शास्त्रीय विरासत कि prototype कभी नहीं का उपयोग करता है को लागू करते हैं। यह एक बुरा कोडिंग व्यायाम है, लेकिन आप असली शास्त्रीय विरासत जो हमेशा मूलरूप विरासत की तुलना में सिखा देगा:

:

function Person(name, age){ 
    this.name = name; 
    this.age = age; 
    this.sayHello = function(){return "Hello! this is " + this.name;} 
} 

एक और cunstructor है कि यह से विरासत करें:

एक custructor बनाओ

function Student(name, age, grade){ 
    Person.apply(this, [name, age]); 
    this.grade = grade 
} 

बहुत आसान! Student कॉल (लागू) Personname और age तर्कों के साथ स्वयं grade तर्कों का ख्याल रखता है।

अब Student का उदाहरण दें।

var pete = new Student('Pete', 7, 1); 

आउट pete वस्तु अब name, age, grade और sayHello गुण शामिल होंगे। यह उन सभी संपत्तियों का मालिक है। वे प्रोटोटाइप के माध्यम से Person पर अपलिंक नहीं हैं। अगर हम इस को Person बदलने के लिए:

function Person(name, age){ 
    this.name = name; 
    this.age = age; 
    this.sayHello = function(){ 
    return "Hello! this is " + this.name + ". I am " this.age + " years old"; 
    } 
} 

होगा pete कोई recieve अद्यतन। अगर हम pete.sayHello पर कॉल करते हैं, तो टी Hello! this is pete वापस आ जाएगा। यह नया अपडेट नहीं मिलेगा।

0
समुचित उपयोग जावास्क्रिप्ट-प्रोटोटाइप आधारित विरासत के लिए

आप इस्तेमाल कर सकते हैं fastClasshttps://github.com/dotnetwise/Javascript-FastClass

आप सरल inheritWith स्वाद:

var Mammal = function (spec) { 
    this.spec = spec; 
}.define({ 
    clearThroat: function() { return "Ahem" }, 
    getName: function() { 
     return this.spec.name; 
    }, 
    says: function() { 
     return this.clearThroat() + ' ' + spec.saying || ''; 
    } 
}); 

var Cat = Mammal.inheritWith(function (base, baseCtor) { 
    return { 
     constructor: function(spec) { 
      spec = spec || {}; 
      baseCtor.call(this, spec); 
     }, 
     purr: function() { 
      return this.clearThroat() + " purr"; 
     }, 
     getName: function() { 
      return this.says() + ' ' + this.spec.name + this.says(); 
     } 
    } 
}); 

var kitty = new Cat({ name: "Fluffy" }); 
kitty.purr(); // Ahem purr 
kitty.getName(); // Ahem Fluffy Ahem 

और अगर आप प्रदर्शन के बारे में बहुत चिंतित हैं तो आप fastClass स्वाद:

var Mammal = function (spec) { 
    this.spec = spec; 
}.define({ 
    clearThroat: function() { return "Ahem" }, 
    getName: function() { 
     return this.spec.name; 
    }, 
    says: function() { 
     return this.clearThroat() + ' ' + spec.saying || ''; 
    } 
}); 

var Cat = Mammal.fastClass(function (base, baseCtor) { 
    return function() { 
     this.constructor = function(spec) { 
      spec = spec || {}; 
      baseCtor.call(this, spec); 
     }; 
     this.purr = function() { 
      return this.clearThroat() + " purr"; 
     }, 
     this.getName = function() { 
      return this.says() + ' ' + this.spec.name + this.says(); 
     } 
    } 
}); 

var kitty = new Cat({ name: "Fluffy" }); 
kitty.purr(); // Ahem purr 
kitty.getName(); // Ahem Fluffy Ahem 

बीटीडब्ल्यू, आपका प्रारंभिक कोड कोई भी नहीं बनाता है समझ में आया लेकिन मैंने इसका शाब्दिक सम्मान किया है।

fastClass उपयोगिता:

Function.prototype.fastClass = function (creator) { 
    var baseClass = this, ctor = (creator || function() { this.constructor = function() { baseClass.apply(this, arguments); } })(this.prototype, this) 

    var derrivedProrotype = new ctor(); 

    if (!derrivedProrotype.hasOwnProperty("constructor")) 
     derrivedProrotype.constructor = function() { baseClass.apply(this, arguments); } 

    derrivedProrotype.constructor.prototype = derrivedProrotype; 
    return derrivedProrotype.constructor; 
}; 

inheritWith उपयोगिता:

Function.prototype.inheritWith = function (creator, makeConstructorNotEnumerable) { 
    var baseCtor = this; 
    var creatorResult = creator.call(this, this.prototype, this) || {}; 
    var Derrived = creatorResult.constructor || 
    function defaultCtor() { 
     baseCtor.apply(this, arguments); 
    }; 
    var derrivedPrototype; 
    function __() { }; 
    __.prototype = this.prototype; 
    Derrived.prototype = derrivedPrototype = new __; 

    for (var p in creatorResult) 
     derrivedPrototype[p] = creatorResult[p]; 

    if (makeConstructorNotEnumerable && canDefineNonEnumerableProperty) //this is not default as it carries over some performance overhead 
     Object.defineProperty(derrivedPrototype, 'constructor', { 
      enumerable: false, 
      value: Derrived 
     }); 

    return Derrived; 
}; 

define उपयोगिता:

Function.prototype.define = function (prototype) { 
    var extendeePrototype = this.prototype; 
    if (prototype) 
     for (var p in prototype) 
      extendeePrototype[p] = prototype[p]; 
    return this; 
} 

[* अस्वीकरण, मैं खुला स्रोत पैकेज और नाम के लेखक हूँ विधियों का नाम बदलकर बदला जा सकता है भविष्य` *]

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