-
-
Save aroc/5715154 to your computer and use it in GitHub Desktop.
// Allows you to create a child which is a copy of the parent and changing the child or parent doesn't affect one another. | |
// Calling "this" inside the child won't change attributes of the parent, as it is a copy and not connected through the prototype chain. | |
define(['jquery', 'underscore', 'backbone'], function ($, _, Backbone) { | |
// NOTE: This works in every scenario I've tested it in. However, this code looks bad | |
// and there may very well be a much cleaner + better way to handle this. Or maybe not | |
// because JS prototypes are crazy. | |
function childOfClass (parentFunction, newAttributes) { | |
// Create the new function and ensure to call Backbone's standard constructor | |
// with the context of *this* (this function). | |
// NOTE: We could change this to be the constructor of the parentFunction in order to | |
// have the parentFunction constructor code ran, then add in a call to | |
// this.initialize.apply(this, arguments) to *also* run this function's initialize method upon | |
// object construction. | |
function childFunction () { | |
Backbone.Model.prototype.constructor.apply(this, arguments); | |
} | |
// Set the prototype equal to that of a NEW parentFunction. We do new | |
// parentFUnction instead of just parentFunction or parentFunction.prototype | |
// because this breaks the prototype chain and allows us to inherit a *copy* of the | |
// parentFunction's attributes. | |
childFunction.prototype = new parentFunction(); | |
// After we've set the prototype equal to that of the parentFunction, ensure | |
// the constructor is set to the childFunction function, or the Backbone.Model | |
// constructor code won't get run when the object is created. | |
childFunction.prototype.constructor = childFunction; | |
// Extend the prototype with the new / additional functionality. | |
_.extend(childFunction.prototype, newAttributes); | |
// Return the new function / class. | |
return childFunction; | |
} | |
return childOfClass; | |
}); |
Ya @kastiglione that should work. The issue with the previous solutions is that we are needing a deep copy of the validations object.
We tried that here a couple days ago. It does work, but the problem is I need to deep copy every attribute I want to from UserModel over to SignupModel. I'd prefer if I didn't need to go about it that way.
We tried doing a deep copy of the UserModel's prototype, but couldn't manage to get it working properly - it still got overridden.
The issue is that hasOwnProperty will only look at the immediate object and won't navigate the prototype chain. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
hasOwnProperty is only good for telling where the function/object is defined, not if the object will respond to the function. For that I would call it and see if you get 'undefined', unless there is a better way.
Add the following to your fiddle and you'll see it works fine.
alert((new UserModel).validation['user']['type']);
alert((new SignupModel).validation['user']['type']);
Unless I am missing something from your fiddle.
The other thing to be aware of is that it appears Backbone defines it's own extend function. If you are looking at the one in underscore, you are looking in the wrong place. It's at the bottom of the page. http://backbonejs.org/docs/backbone.html
@tylermercier The parts in the gist about hasOwnProperty
were from me, but they're irrelevant. See the last two comments by @ekryski and @aroc. Basically, they want deep copying of a number of properties from the parent's prototype, but they don't want to explicitly do that in each subclass initializer.
I haven't tried it, but try adding
this.validation = $.extend(true, {}, this.validation)
to get a local deep copy of thevalidation
hash.http://api.jquery.com/jQuery.extend/#jQuery-extend-deep-target-object1-objectN