Fix JavaScript Inheritance

I read a lot of articles on "inheritance" in javascript. Some of them use new , while others recommend Object.Create . The more I read, the more confusing, because it seems that there are an infinite number of options for solving inheritance.

Could someone be kind to show me the most acceptable way (or the standard standard, if any)?

(I want to have a base Model object that I can extend with RestModel or LocalStorageModel .)

+13
javascript
Jun 05 2018-12-06T00:
source share
2 answers

Simple: Object.create not supported in all environments, but can be adjusted using new . In addition, they have different goals: Object.create simply creates an object that inherits from another, and new also calls the constructor function. Use what fits.

In your case, it seems to you that RestModel.prototype inheriting from Model.prototype . Object.create (or its laying) is the right way because you do not want to: a) create a new instance (create an instance of new Model ) and b) do not want to call the Model constructor:

 RestModel.prototype = Object.create(Model.prototype); 

If you want to call the Model constructor in RestModels, this has nothing to do with prototypes. Use call() or apply() to do this:

 function RestModel() { Model.call(this); // apply Model constructor on the new object ... } 
+11
Jun 05 2018-12-12T00:
source share

JavaScript is an OOP language based on prototypes, not classes. This is one of the reasons for all this confusion that you can see around: many developers use JS as it was a class.

So you can see many libraries trying to use the class-based language paradigm in JS.

In addition, JS itself lacks some of the traits that inherit, as well as prototype-based, painful ones. For example, before Object.create there was no way to create an object from another object (as the language should be based on the OOP prototype), but only using the function as constructor.

And for this reason, you can see many libraries that are trying to "fix" the language, each in its own way.

So your confusion is normal. Let's say that the β€œofficial” way is to use the prototype , function property as a constructor and Object.create to create from an insteance object. However, as mentioned above, in some cases, the code is detailed or lacks functionality, so this procedure often wraps up in some way, and then becomes a matter of personal taste.

Since you are talking about a model, you can take a look at the Trunk model and see if this approach suits you.

Update : to give an example, which I hope will help you clarify, here is the old way to inherit from school using new :

 function Model() { this.foo = "foo"; this.array = []; } Model.prototype.foo = ""; Model.prototype.array = null; Model.prototype.doNothing = function() {}; function RestModel() { this.bar = "bar"; } RestModel.prototype = new Model; RestModel.prototype.bar = "" var myModel = new RestModel(); 

Now, here are the problems:

  • The Model constructor is called only once when RestModel.prototype installed. Therefore, the foo property for each instance of RestModel will be "foo".
  • Not only that, but all instances of RestModel will have the same instance of the same array in the this.array property. If you instantiate the Model directly, you have a new array instance for each instance.
  • myModel.constructor Model instead of RestModel . This is because we are redefining prototype with a new instance of Model that contains a constructor equal to Model .
  • If you want to have a new instance of RestModel with a lazy constructor call, this is not possible.

I think that there are main points, of course, they are not the only ones. So how to solve these problems? As I said, many people have already done this, and they create a library and framework to limit verbosity. However, to have an idea:

 function Model() { this.foo = "foo"; this.array = []; } Model.prototype.foo = ""; Model.prototype.array = null; Model.prototype.doNothing = function() {}; function RestModel() { Model.call(this); this.bar = "bar"; } RestModel.prototype = Object.create(Model.prototype); RestModel.prototype.constructor = RestModel; RestModel.prototype.bar = "" var myModel = new RestModel(); // for lazy constructor call var anotherModel = Object.create(RestModel.prototype); RestModel.call(anotherModel); 

Note that if you do not want to use prototype or function as a constructor, using Object.create you can do this:

 var Model = { foo: "", array: null, doNothing: function() {} } var RestModel = Object.create(Model); RestModel.bar = ""; var myModel = Object.create(RestModel); // Assuming you have to set some default values initialize(RestModel); 

Or:

 var Model = { foo: "", array: null, doNothing: function() {}, init : function () { this.foo = "foo"; this.array = []; }, } var RestModel = Object.create(Model); RestModel.bar = ""; RestModel.init = function () { Model.init.call(this); this.bar = "bar"; } var myModel = Object.create(RestModel); myModel.init(); 

In this case, you basically mimic the constructor. You can also pass descriptor to Object.create (see docs ), but it becomes more verbose. Most people use a kind of function or extend method (as you probably saw in the Backbone example).

Hope this helps!

+10
Jun 05 2018-12-12T00:
source share



All Articles