1

I'm stuck on figuring out how to do multi-level inheritance while using Object.create() as opposed to traditional constructors. I've opened a fiddle here .

We have two types of objects, programmers, and a "subclass" front-end developers. Programmers inherits from the programmer prototype object, and as you can see, all programmers can be awkward.

var programmerProto = Object.create(Object.prototype,{    
   beAwkward: {value: function(){
          return "Yeah I uhh, AHEM, *shuffles feet*";
   }
  }    
});

function programmerFactory (name, age, neckbeard){
  return Object.create(programmerProto, {
    name: {writable: true, enumerable: true, value: name},
    age: {writable: false, enumerable: true, value: age},
    neckbeard: {writable: true, enumerable: true, value: neckbeard}
  });
}

Now for frontend developers, they have their own common traits, so we need a new prototype object as defined. But, front-end devs are also programmers, so we make the front-end prototype object as follows:

 var frontEndProto = Object.create(programmerProto, {
   beSmooth: {
     value: function(){
                 return "Excuse me ma'am, could I interest you in a, fish sandwich?";
             }        
 },
   preferredLanguage: {writable: true, enumerable: true, value: 'JS'}
});

Now we hit the problem. I want to use a factory method to create instances of the frontend developers, so I can add some front-end specific property like "CSS3_skillz" or something. But if I use Object.create(frontEndProto, "..."), that ... is going to be all the code I already wrote in the programmerFactoryFunction. If I call programmerFactory from within frontEndFactory, then the prototype of the returned object is programmerProto instead of frontEndProto. What's the proper way to handle this?

2 Answers 2

2

I think you're going a bit overboard on the inheritance chain thing and the use of Object.defineProperty()-style properties.

Unless you have a strong reason to need things like instanceof, you can just use an .extend() function to implement your inheritance. I'm using the underscore/lodash _.extend() function below, but you could use pretty much any implementation of it:

var programmerProto = {    
    beAwkward: function(){
        return "Yeah I uhh, AHEM, *shuffles feet*";
    }
};

function programmerFactory (name, age, neckbeard){
    return _.extend({
        name: name,
        age: age,
        neckbeard: neckbeard
    }, programmerProto);
}

var frontEndProto = {
    beSmooth: function(){
        return "Excuse me ma'am, could I interest you in a, fish sandwich?";
    },
    preferredLanguage: 'JS'
};

function frontEndFactory(name, age, css3Skillz) {
    return _.extend(programmerFactory(name, age, true), {
        css3Skillz: css3Skills
    }, frontEndProto);
}

I think this talk on this topic is pretty good:
http://www.youtube.com/watch?v=PV_cFx29Xz0&t=28m57s

Sign up to request clarification or add additional context in comments.

4 Comments

This makes sense. I was stuck in the mindset that I needed to use Object.create to specifcy the prototype, but extension does the trick without the hassle of using property descriptors. My only concern is, doesn't this make each 'instance' heavier? The properties of the prototype are no longer sitting in the prototype chain, but are instead attached to each instance, correct?
@Derek Yes, there is the possibility that your objects could take up a few extra bytes because they have direct references to their properties, but remember that the prototype chain is not without costs either. With a prototype chain, you've got both the memory costs of the chain itself, and the CPU costs of walking that chain every time a property is accessed. Douglas Crockford discusses that very point at 33:50 here, and his conclusion is that memory is cheap, CPU cycles are not, so ditch the prototype chain.
OK that's a good explanation. Just for my own sanity, the new properties we get on the 'instance' via extend, those properties are just holding references to the methods on the prototype-like object correct? but if we have primitives on the prototype-like object then the 'instance' would have complete copies?
@Derek Yes, that's correct. It would copy primitives in entirety, and objects (including strings and functions) as references.
1

A solution to your problem here lies in appending properties of one object to another is useful here.

First, the append function I use -

var appendObject = function(obj, toAppend) { 
    Object.keys(toAppend).forEach(function(el) { 
        Object.defineProperty(obj, el, Object.getOwnPropertyDescriptor(toAppend,el)); 
    }); 
    return obj; 
}

What this does is pretty simple - it walks through toAppend's properties and uses their property descriptors to define new properties on obj. It is mutating obj, but returns it as well so you can chain it if you needed to.

With this function, you can them have the frontEndDevFactory be implemented like this -

function frontEndDevFactory (name, age, pullupCount, rockStar){
    var programmer = programmerFactory(name, age); 
    var newDev = Object.create(frontEndProto, {
        pullupCount: {writable: true, enumerable: true, value: pullupCount},
        rockStar: {writable: false, enumerable: true, value: rockStar}
    }); 
    appendObject(newDev, programmer); 
    return newDev; 
}

Here's a fiddle modifying your code that demonstrates this.

1 Comment

I think this example alleviates my concern about the post from @JLRishe. Now, instead of having the properties of the prototype sitting directly on the object, newDev has it's proper prototype, and newDev prototype is extended from Programmer.prototype.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.