Javascript classes are preferred because they are modular and reusable (when well designed). Frequently, Javascript classes are paired with HTML elements, and there may be many instances of a class on a page. For example, the qbo3.Dropdown class fetches dropdown lists from the server. For example, the following code snippet demonstrates the use of 'this': qbo3.Dropdown = new Class({ Implements: [Options, Events], ... initialize: function (options) { this.setOptions(options); this.target = document.id(this.options.target); ... }, refresh: function (data) { new Request.JSON({ ... onSuccess: function (json, text) { this.target ... }.bind(this), // ensure when calling onSuccess, it's for the correct instance of qbo3.Dropdown onFailure: function (xhr) { this.target ... }.bind(this) // ensure when calling onSuccess, it's for the correct instance of qbo3.Dropdown }).send(); }, ... }); In the example above, if we did not use onSuccess: function() {...}.bind(this) , when the success function was called, the function would not "remember" what the options are, what HTML element it's bound to (this.target), or anything else to do with this.One can avoid the use of 'this' by creating a closure around a declared variable, such as 'self'. (One can use any variable name one want's, 'bob' works. 'self' is just convention.) qbo3.Dropdown = new Class({ Implements: [Options, Events], ... initialize: function (options) { var self = this; self.setOptions(options); self.target = document.id(self.options.target); ... }, refresh: function (data) { var self = this; new Request.JSON({ ... onSuccess: function (json, text) { self.target ... }, // no binding required onFailure: function (xhr) { self.target ... } // no binding required }).send(); }, ... });
No binding is required as long as the function refers to self, instead of this, since the value of 'self' will be included in the function definition. Using 'this' does not create a closure; only local variables do. This does not mean we should use self for everything, and abandon the use of 'this'. There are two reasons to not use 'self':
The second is a more common scenario. In the example above, let's assume the onSuccess method was complex. Instead of declaring the function 'inline', we can bind to a function that is a method of the class: qbo3.Dropdown = new Class({ Implements: [Options, Events], ... initialize: function (options) { var self = this; self.setOptions(options); self.target = document.id(self.options.target); ... }, refresh: function (data) { var self = this; new Request.JSON({ ... onSuccess: self.render.bind(self) , // binding is required; we can use 'self' or 'this' onFailure: function (xhr) { self.target ... } // no binding required }).send(); }, render: function(json, text) { this.target } ... }); Note the use of self.render.bind(self) ; one could have used this.render.bind(this) instead. They are functionally equivalent.This brings up another reason to use 'self': javascript minification. Minification will "compress" javascript code, making smaller class files to download. Minifiers use techniques including:
Note that 'this' is not a local variable, but 'self' is. Thus, minifying this: initialize: function(options) { this.setOptions(options); this.target = document.id(options.target); this.target.store(this.options.storageKey, this); } becomes this (leaving white space alone): initialize: function(o) { this.setOptions(o); this.target = document.id(o.target); this.target.store(this.options.storageKey, this); } Introducing 'self' buys us a bit of a smaller download: initialize: function(options) { var self = this; self.setOptions(options); self.target = document.id(options.target); self.target.store(self.options.storageKey, self); } becomes this (leaving white space alone): initialize: function(o) { var s = this; s.setOptions(o); s.target = document.id(o.target); s.target.store(s.options.storageKey, s); } In short, if you use 'this' more than 4-5 times within a function, consider using 'self' simply to reduce download times. |