/constructors.md Secret
Last active
January 4, 2016 00:49
Revisions
-
aron revised this gist
Jan 21, 2014 . 1 changed file with 6 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -11,7 +11,7 @@ var MyView = Backbone.View.extend({ }); ``` In the background this returning a throw-away constructor object to create the new instance, and then calling `.initialize` to handle setup. The up-side of this, and the only reason I can see for it's existence, is that we don't have to call the parent `Backbone.View` method with our new instance. The downside to this is that it removes the benefits of having a named function as the constructor. Namely debugging and introspection. @@ -96,4 +96,8 @@ new MyView({model: SuperModel}); //=> error: "MyView expected model option to be an AwesomeModel instance but received a SuperModel instance" ``` So, I suggest that we phase out the use of `.initialize` and instead pass constructors. The functionality is the same, and all it requires is naming the constructor function and calling the parent constructor. Benefits are clearer code, the inheritance pattern is visible and consistent with extending other methods, and better visual output in browsers consoles that support it. This is something that can be introduced incrementally without disrupting the existing codebase. But will improve readability as it's introduced. -
aron created this gist
Jan 21, 2014 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,99 @@ Using named constructors ------------------------ The general usage of a Backbone class is to use the `.extend` method providing an `.initialize` method. ```js var MyView = Backbone.View.extend({ initialize: function () { // Setup object. } }); ``` In the background this returning a throw-away constructor object to create the new instance, and then calling `.initialize` to handle setup. The up side of this is that we don't have to call the `Backbone.View` method with our new instance. The downside to this is that it removes the benefits of having a named function as the constructor. Namely debugging and introspection. ``` var MyView = Backbone.View.extend({}); MyView.name //=> "" new MyView().constructor.name //=> "" function MyOtherView() { Backbone.View.apply(this, arguments); } MyOtherView.name //=> "MyOtherView" new MyOtherView().constructor.name //=> "MyOtherView" ``` Using the Chrome console to inspect objects is a common task, and without named constructors it can be confusing as to which type of object you are looking at. Take the following example: ```js var Car = Backbone.Model.extend({initialize: function () {}}); var Bus = Backbone.Model.extend({initialize: function () {}}); var Van = Backbone.Model.extend({initialize: function () {}}); var VehicleCollection = Backbone.Collection.extend({initialize: function () {}}); var GarageView = Backbone.View.extend({initialize: function () {}}); var vehicles = new VehicleCollection(); vehicles.add(new Car()); vehicles.add(new Car()); vehicles.add(new Bus()); vehicles.add(new Van()); var garageView = new GarageView({collection: vehicles}); ```  Backbone allows us to pass our own constructor into `.extend` and can be used in place of `.initialize` and is closer to a bare JavaScript inheritance style. This gives us much clearer output in the Chrome console. ```js var Car = Backbone.Model.extend({constructor: function Car() { Backbone.Model.apply(this, arguments); }}); var Bus = Backbone.Model.extend({constructor: function Bus() { Backbone.Model.apply(this, arguments); }}); var Van = Backbone.Model.extend({constructor: function Van(){ Backbone.Model.apply(this, arguments); }}); var VehicleCollection = Backbone.Collection.extend({constructor: function VehicleCollection() { Backbone.Collection.apply(this, arguments); }}); var GarageView = Backbone.View.extend({constructor: function GarageView() { Backbone.View.apply(this, arguments); }}); var vehicles = new VehicleCollection(); vehicles.add(new Car()); vehicles.add(new Car()); vehicles.add(new Bus()); vehicles.add(new Van()); var garageView = new GarageView({collection: vehicles}); ```  This also allows us to provide more debugging information when passed the incorrect data. For example if we require a specific model type to be passed into a view we can use the name property to provide useful feedback to the developer. ```js constructor: function MyView(options) { Backbone.View.apply(this, arguments); if (!(options.model instanceof AwesomeModel)) { var modelName = options.model.name || "unknown"; throw new Error("MyView expected model option to be an AwesomeModel instance but received a " + modelName + " instance"); } } // Later new MyView({model: SuperModel}); //=> error: "MyView expected model option to be an AwesomeModel instance but received a SuperModel instance" ``` This is something that can be introduced incrementally without disrupting the existing codebase. But will improve readability as it's introduced.