简体   繁体   中英

Interesting JavaScript inheritance pattern

I have recently watched a video where Douglas Crockford was explaining inheritance patterns of Javascript. The video itself is pretty old - it was filmed 6 years ago - but still useful. In that video he showed one inheritance pattern he kinda invented (although I am not sure who the author is). This is the code using his approach:

 // imitation of new operator function objectConstructor(obj, initializer, methods) { // create prototype var func, prototype = Object.create(obj && obj.prototype); // add methods to the prototype if(methods) Object.keys(methods).forEach(function(key) { prototype[key] = methods[key]; }); // function that will create objects with prototype defined above func = function() { var that = Object.create(prototype); if(typeof initializer === 'function') initializer.apply(that, arguments); return that; } func.prototype = prototype; prototype.constructor = func; return func; } var person = objectConstructor(Object, function(name) { this.name = name; }, { showName: function() { console.log(this.name); } }); var employee = objectConstructor(person, function(name, profession) { this.name = name; this.profession = profession; }, { showProfession: function() { console.log(this.profession); } }); var employeeInfo = employee('Mike', 'Driver'); employeeInfo.showName(); // Mike employeeInfo.showProfession(); // Driver 

Unfortanately, he didn't show the invocation. So, this part

var employeeInfo = employee('Mike', 'Driver');
employeeInfo.showName();
employeeInfo.showProfession();

is mine. It generally works, but it turns out that I repeat this.name = name; for both "classes" - person and employee . I played around but I didn't manage to make it work properly without that repetition. Seems I cannot get name because such a property isn't contained in the prototypal chain for employee . I didn't succeed either in mixing in stuff like person.call(this, arguments) . So, apart from whether it is cool/nice/smart/sensible etc. or not in 2017, how could I remove this.name = name; from employee and get the same result? Or everything is ok and this approach doesn't suppose it?

Since the func constructor completely disregards this , passing any context to it via call or apply will not work. Creating a way to copy over the super class' properties after creating an object is one of the ways you could accomplish your task.

 // imitation of new operator function objectConstructor(obj, initializer, methods) { // create prototype var func, prototype = Object.create(obj && obj.prototype); // add methods to the prototype if(methods) Object.keys(methods).forEach(function(key) { prototype[key] = methods[key]; }); // function that will create objects with prototype defined above func = function() { var that = Object.create(prototype); if(typeof initializer === 'function') initializer.apply(that, arguments); return that; } func.prototype = prototype; prototype.constructor = func; return func; } function copyProperties(source, target) { for (var prop in source) { if (source.hasOwnProperty(prop)) { target[prop] = source[prop]; } } } var person = objectConstructor(Object, function(name) { this.name = name; }, { showName: function() { console.log(this.name); } }); var employee = objectConstructor(person, function(name, profession) { copyProperties(person.apply(null, arguments), this); this.profession = profession; }, { showProfession: function() { console.log(this.profession); } }); var employeeInfo = employee('Mike', 'Driver'); employeeInfo.showName(); // Mike employeeInfo.showProfession(); // Driver 

Here is your snippet with 2 small modifications so that you can do a super(name) type of call.

I've placed comments were I've made the modifications.. with prefix keith:

 // imitation of new operator function objectConstructor(obj, initializer, methods) { // create prototype var func, prototype = Object.create(obj && obj.prototype); // add methods to the prototype if(methods) Object.keys(methods).forEach(function(key) { prototype[key] = methods[key]; }); // function that will create objects with prototype defined above func = function() { var that = Object.create(prototype); if(typeof initializer === 'function') initializer.apply(that, arguments); return that; } func.prototype = prototype; //keith: store the initialization in constructor, //keith: as func is already creating the object.. prototype.constructor = initializer; return func; } var person = objectConstructor(Object, function(name) { this.name = name; }, { showName: function() { console.log(this.name); } }); var employee = objectConstructor(person, function(name, profession) { //keith: call our super person(name) person.prototype.constructor.call(this, name); this.profession = profession; }, { showProfession: function() { console.log(this.profession); } }); var employeeInfo = employee('Mike', 'Driver'); employeeInfo.showName(); // Mike employeeInfo.showProfession(); // Driver 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM