Created
January 29, 2012 21:41
-
-
Save gordonbrander/1700841 to your computer and use it in GitHub Desktop.
jQuery-style Instantiation: Decorate a Constructor Function to Enforce `new` and `return this`
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 characters
// Takes a function and wraps it, making sure: | |
// | |
// * It enforces `new` | |
// * It returns `this` | |
// | |
// Doing this enables a jQuery coding style for object creation, | |
// where constructor functions become chain-able immediately after | |
// construction, and don't have to be called with `new`. For example: | |
// | |
// var F = decorateCtor(function (a, b, c) { ... }); | |
// F.prototype.rock = 'on'; | |
// F(1, 2, 3).rock; | |
// >> 'on' | |
var decorateCtor = (function () { | |
// Fast lookups. | |
var bind = Function.prototype.bind, | |
slice = Array.prototype.slice; | |
return function (callback) { | |
// Return a new function -- the "decoration" wrapper function. | |
return function Ctor () { | |
if (!(this instanceof Ctor)) { | |
// Capture the arguments in array format. | |
var args = slice.call(arguments); | |
// Add `null` to the beginning.. this is our "context" | |
// for bind -- i.e. no context, since calling new overrides | |
// bound contexts but not bound arguments. | |
// See <http://dmitrysoshnikov.com/notes/note-1-ecmascript-bound-functions/#constructor-with-various-number-of-arguments> | |
args.unshift(null); | |
// Bind the arguments (in array format) to the constructor, | |
// creating a new bound function. | |
var boundCtor = bind.apply(Ctor, args); | |
// Initialize the constructor with bound arguments. | |
return new boundCtor(); | |
} | |
callback.apply(this, arguments); | |
return this; | |
}; | |
}; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If you use this in older browsers, you'll also want to include a shim for Function.prototype.bind (don't worry, it's pretty small).
Some background on the technique: