2009-10-29 21 views
16

मैं टीडीडी जावास्क्रिप्ट पर ebook on GitHub पर काम कर रहा हूं और मुझे आश्चर्य है कि क्या मुझे कोई लोकप्रिय विरासत पैटर्न याद आ रहा है। यदि आप किसी भी अतिरिक्त पैटर्न के बारे में जानते हैं तो मुझे उन्हें देखना अच्छा लगेगा। वे निम्नलिखित होना चाहिए:लोकप्रिय जावास्क्रिप्ट विरासत पैटर्न

  1. समय परीक्षण किया - असली क्षुधा
  2. स्रोत कोड आपूर्ति की जानी चाहिए में इस्तेमाल किया। जितना संभव हो सके सीधे आगे और पैडेंटिक होना चाहिए।
  3. बेशक सही और काम करना सही है।

कारण यह है कि ऐसा करने का कारण यह है कि ऐसा लगता है कि जावास्क्रिप्ट में ऑब्जेक्ट विरासत हमारे लिए बहुत मुश्किल है। मेरा जावास्क्रिप्ट विरासत अध्याय मूल रूप से एक अध्ययन सहायता है: क्रॉकफोर्ड के गुड पार्ट्स और वेब डेवलपर्स के लिए जकास की व्यावसायिक जावास्क्रिप्ट।

यहाँ पैटर्न हैं मैं अब तक है:

:

// Pseudoclassical Inheritance 
    function Animal(name) { 
     this.name = name; 
     this.arr = [1,2,3]; 
    }; 
    Animal.prototype = { 
     constructor: Animal, 
     whoAmI: function() { return "I am " + this.name + "!\n"; } 
    }; 

    function Dog(name, breed) { 
     this.name = name; 
     this.breed = breed; 
    }; 
    Dog.prototype = new Animal(); 
    Dog.prototype.getBreed = function() { 
     return this.breed; 
    }; 
    Dog.prototype.bark = function() { 
     return 'ruff ruff'; 
    }; 

    // Combination Inheritance 
    function Parent(name) { 
     this.name = name; 
     this.arr = [1,2,3]; 
    }; 
    Parent.prototype = { 
     constructor: Parent, 
     toString: function() { return "My name is " + this.name; } 
    }; 
    function Child(name, age) { 
     Parent.call(this, name); 
     this.age = age; 
    }; 

    Child.prototype = new Parent(); 

    Child.prototype.getAge = function() { 
     return this.age; 
    }; 

    // Prototypal Inheritance 
    var helper = { // Thanks to Bob Vince for reminding me NOT to clobber Object! 

     inherit: function(p) { 
     NewObj = function(){}; 
     NewObj.prototype = p; 
     return new NewObj(); 
     }, 
     inheritPrototype: function(subType, superType) { 
     var prototype = helper.inherit(superType.prototype); 
     prototype.constructor = subType; 
     subType.prototype = prototype; 
     } 
    }; 

    function SubType(name, age) { 
     Parent.call(this, name); 
     this.age = age;  
    }; 
    //Child.prototype = new Parent(); // Gets replaced by: 
    helper.inheritPrototype(SubType, Parent); 
    SubType.prototype.getAge = function() { 
     return this.age; 
    }; 

    // Functional - Durable Pattern 
    function super_func(blueprint) { 
     var obj = {}; 
     obj.getName = function() { return blueprint.name; }; 
     obj.getAge = function() { return blueprint.age; }; 
     obj.getFoo = function() { return blueprint.foo; }; 
     obj.getBar = function() { return blueprint.bar; }; 
     return obj; 
    }; 
    function sub_func(blueprint) { 
     blueprint.name = blueprint.name || "Crockford's Place"; 
     supr = super_func(blueprint); 
     supr.coolAugment = function() { return "I give a fresh new perspective on things!" }; 
     return supr;  
    }; 

और उन दिलचस्पी के लिए, यहाँ jspec परीक्षण (खेद है, लेकिन Markdown या जो कुछ भी वे उपयोग कर रहे हैं mangles प्रारूप थोड़ा) कर रहे हैं

describe 'JavaScript Inheritance Tests' 
    before_each 
    animal = new Animal("Onyx") 
    dog = new Dog("Sebastian", "Lab") 

    person = { password : 'secret', toString : function(){ return '<Person>' } } 
    stub(person, 'toString').and_return('Original toString method!')  
    end 
    describe 'Pseudoclassical Inheritance Creation' 
    it 'should create parent and child object using pseudoclassical inheritance' 
     animal.constructor.should.eql Animal 
     // dog.constructor.should.eql Dog // Nope: expected Animal to eql Dog 
     dog.constructor.should.eql Animal 
     animal.should.be_a Animal 
     dog.should.be_a Animal 
     // dog.should.be_a Dog // Nope! We severed the original prototype pointer and now point to Animal! 
     dog.should.be_an_instance_of Animal 
     dog.should.be_an_instance_of Dog 
     (animal instanceof Dog).should.be_false 
    end 
    it 'should behave such that child inherits methods and instance variables defined in parent' 
     animal.whoAmI().should.match /I am Onyx.*/ 
     dog.whoAmI().should.match /Sebastian.*/ 
     animal.should.respond_to 'whoAmI' 
     dog.should.respond_to 'whoAmI' 
     dog.should.have_prop 'name' 
    end 
    it 'should behave such that methods and instance variables added to child are NOT available to parent' 
     dog.bark().should.match /Ruff Ruff/i 
     dog.should.have_property 'breed' 
     dog.should.respond_to 'bark' 
     // animal.should.have_prop 'breed' // Of course not! 
     // animal.should.respond_to 'bark' // Of course not! 
    end 
    it 'should behave such that reference variables on the parent are "staticy" to all child instances' 
     dog.arr.should.eql([1,2,3]) 
     dog.arr.push(4) 
     dog.arr.should.eql([1,2,3,4]) 
     spike = new Dog("Spike", "Pitbull") 
     spike.arr.should.eql([1,2,3,4]) 
     spike.arr.push(5) 
     rover = new Dog("Rover", "German Sheppard") 
     spike.arr.should.eql([1,2,3,4,5]) 
     rover.arr.should.eql([1,2,3,4,5]) 
     dog.arr.should.eql([1,2,3,4,5]) 
    end 
    end 

    describe 'Combination Inheritance Solves Static Prototype Properties Issue' 
    it 'should maintain separate state for each child object' 
     child_1 = new Child("David", 21) 
     child_2 = new Child("Peter", 32) 
     child_1.arr.push(999) 
     child_2.arr.push(333) 
     child_1.arr.should.eql([1,2,3,999]) 
     child_2.arr.should.eql([1,2,3,333]) 
     child_1.getAge().should.eql 21 
     child_1.should.be_a Parent 
    end 
    end 

    describe 'Prototypal Inheritance' 
    it 'should inherit properties from parent' 
     person.toString().should.match /Original toString.*/i 
     person.password.should.eql 'secret' 
     joe = helper.inherit(person) 
     joe.password.should.eql 'secret' 
     joe.password = 'letmein' 
     joe.password.should.eql 'letmein' 
     person.password.should.eql 'secret' 
    end 
    end 

    describe 'Parisitic Combination Inheritance' 
    it 'should use inheritPrototype (to call parent constructor once) and still work as expected' 
     sub = new SubType("Nicholas Zakas", 29) 
     sub.toString().should.match /.*Nicholas Zakas/ 
     sub.getAge().should.eql 29 
     charlie = new SubType("Charlie Brown", 69) 
     charlie.arr.should.eql([1,2,3]) 
     charlie.arr.push(999) 
     charlie.arr.should.eql([1,2,3,999]) 
     sub.arr.should.eql([1,2,3]) 
     sub.should.be_an_instance_of SubType 
     charlie.should.be_an_instance_of SubType 
     (sub instanceof SubType).should.eql true 
     (sub instanceof Parent).should.eql true 
    end 
    end 

    describe 'Functional Durable Inheritance' 
    it 'should hide private variables' 
     sup = new super_func({name: "Superfly Douglas", age: 39, foo: "foo", bar: "bar"}) 
     sup.getName().should.eql 'Superfly Douglas' 
     sup.name.should.be_undefined 
     sup.getAge().should.eql 39 
     sup.age.should.be_undefined 
     sup.getFoo().should.eql 'foo' 
     sup.foo.should.be_undefined 
    end 

    it 'should create a descendent object that inherits properties while maintaining privacy' 
     sub = new sub_func({name: "Submarine", age: 1, foo: "food", bar: "barfly"}) 
     sub.getName().should.eql 'Submarine' 
     sub.name.should.be_undefined 
     sub.getAge().should.eql 1 
     sub.age.should.be_undefined 
     sub.getFoo().should.eql 'food' 
     sub.foo.should.be_undefined 
     sub.getBar().should.eql 'barfly' 
     sub.bar.should.be_undefined 
     sub.coolAugment().should.match /.*fresh new perspective.*/ 
     //sub.should.be_an_instance_of super_func NOPE! 
     //sub.should.be_an_instance_of sub_func NOPE! 
     sub.should.be_an_instance_of Object 
    end 
    end 

end 

धन्यवाद सब! ओह, और यदि आप मेरा निबंध/पुस्तक देखना चाहते हैं तो मुझे फीडबैक प्राप्त करना अच्छा लगेगा: TDD JavaScript at GitHub repo

+0

मैंने कई अलग-अलग परियोजनाओं पर कई तकनीकों की कोशिश की। मेरा पसंदीदा बेस प्रोटोटाइप को तुरंत चालू करने के लिए Object.create() का उपयोग कर रहा है। मेरे ब्लॉग की जांच करें: http://ncombo.wordpress.com/2013/07/11/javascript-inheritance-done-right/ – Jon

उत्तर

8

सारांश के लिए How to "properly" create a custom object in JavaScript? देखें। (और साथ ही, यह लिंक हो सकते हैं के बाद से मैं इतना समय इसे पूरा लिखने बर्बाद!)

इस:

Dog.prototype = नए पशु();

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

Object.prototype.inherit =

के निर्माण के लिए एक बेहतर दृष्टिकोण है, लेकिन Object में कुछ भी प्रोटोटाइप बहुत गरीब स्वाद माना जाता है। यह वस्तुओं के उपयोग को छोटे नक्शे के रूप में गड़बड़ाने और अन्य कोड तोड़ने का जोखिम चलाता है। आप इस सहायक समारोह को कहीं और डाल सकते हैं, उदाहरण के लिए। Function.prototype.subclass

prototype.constructor

निजी तौर पर क्योंकि constructor (फ़ायरफ़ॉक्स और कुछ अन्य ब्राउज़र में लागू के रूप में, नहीं IE के JScript) जावास्क्रिप्ट में एक विशेष अर्थ नहीं है मैं, से बचने के लिए जाते हैं, और कहा कि अर्थ नहीं है क्या constructor यहां करता है और न ही आप ऐसी किसी भी संपत्ति की अपेक्षा करेंगे; यह भ्रमित है और लगभग हमेशा से बचा है। तो यदि कक्षा प्रणाली में उदाहरण में कन्स्ट्रक्टर फ़ंक्शन के लिंक को शामिल करना है तो मैं इसे और कुछ नाम देना पसंद करूंगा।

+0

आपकी प्रतिक्रिया के लिए धन्यवाद। मैं Object.prototype.inherit के बारे में सहमत हूं और मुझे लगता है कि मैं इसे अपने निबंध में उल्लेख करता हूं लेकिन मैं इसे कम से कम कोड पर टिप्पणियों में जोड़ दूंगा और/या इसे रैपर फ़ंक्शन में डाल दूंगा। इसे पकड़ने के लिए धन्यवाद! Dog.prototype = नया पशु() मैं बाद के पैटर्न में विकल्प देता हूं। आपके इनपुट बॉब के लिए धन्यवाद। – Rob

+0

मैं आगे बढ़ गया और ऑब्जेक्ट क्लॉबरिंग ऑब्जेक्ट के विपरीत एक सहायक ऑब्जेक्ट का उपयोग करने के लिए कोड (और उपरोक्त कोड सूची संपादित) को अपडेट किया। – Rob

+0

हाँ, मैं वापस गया और अपना निबंध पढ़ा और मैं कहता हूं: 'निश्चित रूप से आपको बंदर पैच ऑब्जेक्ट की आवश्यकता नहीं है - आप एक रैपर बना सकते हैं जो आपकी इच्छानुसार ऐसी कार्यक्षमता देता है।' बस सादा आलसी !!! मुझे "इसे सही करें" बनाने के लिए धन्यवाद! – Rob

0

मुझे अपने dev/web/stuff फ़ोल्डर में चारों ओर स्थित विभिन्न विरासत पैटर्न के कम से कम आधे दर्जन कार्यान्वयन मिल गए हैं, लेकिन वे ज्यादातर खिलौने हैं।

Function.prototype.derive = (function() { 
    function Dummy() {} 
    return function() { 
     Dummy.prototype = this.prototype; 
     return new Dummy; 
    }; 
})(); 

उदाहरण कोड:

function Pet(owner, type, name) { 
    this.owner = owner; 
    this.type = type; 
    this.name = name; 
} 

Pet.prototype.toString = function() { 
    return this.owner + '\'s ' + this.type + ' ' + this.name; 
}; 

function Cat(owner, name) { 
    Pet.call(this, owner, 'cat', name); 
} 

Cat.prototype = Pet.derive(); 

var souris = new Cat('Christoph', 'Souris'); 

एक और दिलचस्प एक है

क्या मैं वास्तव में कभी कभी का उपयोग जावास्क्रिप्ट के डिफ़ॉल्ट छद्म वर्ग आधारित दृष्टिकोण पर निम्नलिखित पतली आवरण विरासत आसान बनाना है निम्नलिखित, जो स्वचालित प्रोटोटाइप दृष्टिकोण में स्वचालित रूप से फैक्ट्री विधियों को जोड़ता है:

var Proto = new (function() { 
    function Dummy() {} 

    this.clone = function() { 
     Dummy.prototype = this; 
     return new Dummy; 
    }; 

    this.init = function() {}; 

    this.create = function() { 
     var obj = this.clone(); 
     this.init.apply(obj, arguments); 
     return obj; 
    }; 
}); 

उदाहरण कोड:

var Pet = Proto.clone(); 

Pet.init = function(owner, type, name) { 
    this.owner = owner; 
    this.type = type; 
    this.name = name; 
}; 

Pet.toString = function() { 
    return this.owner + '\'s ' + this.type + ' ' + this.name; 
}; 

Cat = Pet.clone(); 

Cat.init = function(owner, name) { 
    Pet.init.call(this, owner, 'cat', name); 
}; 

// use factory method 
var filou = Cat.create('Christoph', 'Filou'); 

// use cloning (the proper prototypal approach) 
var red = filou.clone(); 
red.name = 'Red'; 

आप already seen मेरी implementation of classes है।

+0

हाय क्रिस्टोफ! धन्यवाद। तो आपकी व्युत्पन्न विधि वास्तव में मेरी विरासत विधि के समान ही है, सिवाय इसके कि यह बंद हो जाती है और 'स्वयं' कहती है; पैटर्न कन्स्ट्रक्टर चोरी का भी उपयोग करता है - मुझे लगता है कि यह अनिवार्य रूप से एक संयोजन विरासत पैटर्न (प्रोटोटाइप और कन्स्ट्रक्टर चोरी संयुक्त) है। मुझे थोड़ी देर के लिए अन्य पैटर्न पर घूरने की आवश्यकता होगी - मुझे लगता है कि मैं आज रात इसके साथ खेलूँगा और रिपोर्ट करूंगा ;-) क्रिस्टोफ को साझा करने के लिए धन्यवाद। – Rob

1

मेरी पिछली कंपनी के सह-कार्यकर्ता ने लाइब्रेरी विकसित की है जैसे जग 0 विरासत http://www.uselesspickles.com/class_library/। मुझे लगता है कि यह राजेंद्र के सुझावों से कामुक है, सिंटैक्स क्लीनर दिखता है।

मैंने एक लेख लिखा जो उससे संपर्क करने के विभिन्न तरीकों को प्रदर्शित करता है, लेकिन यह सुनिश्चित कर रहा है कि ज्ञात बुरे प्रथाओं से बचा जा सके। http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html, यह है कि यदि आप एक लाइब्रेरी डाउनलोड नहीं करना चाहते हैं, लेकिन बस कुछ कोड पेस्ट करना चाहते हैं जिसे आप अपनी जरूरत के अनुसार सुधार सकते हैं।

1

यहां उल्लेख करने के लिए एक दिलचस्प पैटर्न है: एक जावास्क्रिप्ट कन्स्ट्रक्टर किसी ऑब्जेक्ट को वापस कर सकता है (आवश्यक नहीं यह)। कोई एक कन्स्ट्रक्टर फ़ंक्शन बना सकता है, जो प्रॉक्सी ऑब्जेक्ट देता है, जिसमें "असली" इंस्टेंस ऑब्जेक्ट की "असली" विधियों के लिए प्रॉक्सी विधियां होती हैं। यह जटिल लग सकता है, लेकिन यह नहीं है; यहाँ एक कोड का टुकड़ा है:

var MyClass = function() { 
    var instanceObj = this; 
    var proxyObj = { 
     myPublicMethod: function() { 
      return instanceObj.myPublicMethod.apply(instanceObj, arguments); 
     } 
    } 
    return proxyObj; 
}; 
MyClass.prototype = { 
    _myPrivateMethod: function() { 
     ... 
    }, 
    myPublicMethod: function() { 
     ... 
    } 
}; 

अच्छी बात यह है कि प्रॉक्सी निर्माण, स्वचालित किया जा सकता है अगर हम संरक्षित तरीकों के नामकरण के लिए एक सम्मेलन को परिभाषित है। मैंने एक छोटी लाइब्रेरी बनाई जो वास्तव में यह करता है: http://idya.github.com/oolib/

0

यहां पार्टी के लिए देर है लेकिन मेरे पास 2 अंक हैं।

1) कृपया लोगों को सुपरटेप ऑब्जेक्ट्स बनाने के माध्यम से प्राप्त करने के लिए सूचित न करें। इसे किसी कारण से खराब अभ्यास माना जाता है। सबसे पहले, यह एक सिद्धांत गलती है। आप वस्तुओं को तुरंत अपने तरीकों का उपयोग करने के लिए तत्काल कर रहे हैं और प्रति उदाहरण के साथ कुछ भी नहीं कर रहे हैं। ऐसा करने का सही तरीका Object.prototype.inherit विधि का उपयोग करना है। इसके अतिरिक्त, यह विधि आपको सुपरटेप कन्स्ट्रक्टर फ़ंक्शन तर्क खाली छोड़ने के लिए मजबूर करती है, जो सख्त परिस्थितियों में त्रुटि उत्पन्न कर सकती है।

2) आप निर्माता स्टीलिंग पैटर्न का उल्लेख करना भूल गए हैं।

function Supertype(name){ 
this.name=name; 
this.sayName = function(){console.log(this.name);}; 
} 

function Subtype(name){ 
//inherit by using (stealing) supertype constructor function 
Supertype(name); 

// child specific properties 
// 
} 
संबंधित मुद्दे