When should I automatically create an object even if `new` is forgotten?
Let us say I have the following object constructor:
function Foo(bar) {
this.bar = bar;
}
If I run the function in the global scope without the new
keyword then bar
will be set in whatever scope Foo()
is called in:
var foo = Foo(42);
console.log(bar); // 42
console.log(foo.bar); // ERROR
So my idea is to do something like this:
function Foo(bar) {
if(!(this instanceof Foo)) {
// return a Foo object
return new Foo(bar);
}
this.bar = bar;
}
That way if I do new Foo(42)
or Foo(42)
, it would always return a Foo
object.
Is this ever a good idea? If so, when? When (and why) would it be wise to avoid this technique?
This can be useful for when you would like to internally construct an object wrapper.
A little known library internally uses this approach, jQuery.
They do not use the instanceof
approach any longer though. Every time jQuery is called, it automatically does this:
// Define a local copy of jQuery
jQuery = function( selector, context ) {
// Need init if jQuery is called (just allow error to be thrown if not included)
return new jQuery.fn.init( selector, context );
}
Everything it does internally references this local copy. At the very end of its work, it then attaches it to the global scope
window.jQuery = window.$ = jQuery;
So every time you call $()
it internally uses new
. It is also assuming that you do not use new
externally, but it really doesn't care if you do or not.
edit
jsFiddle Demo
//Foo entrance
function Foo(bar){
//construct a new Foo object to return
return new Foo.prototype.build(bar);
}
//constructor for returning new prototype
Foo.prototype.build = function(bar){
//initialize base settings
this.bar = bar;
//chain object
return this;
};
//this is the complex part
//tie the prototype of Foo.prototype.build.prototype to Foo.prototype
//so that is "seems" like Foo is the parent of the prototype assignments
//while allowing for the use of returning a new object in the Foo entrance
Foo.prototype.build.prototype = Foo.prototype;
//simple expansions at this point, nothing looks too different
//makes a function for a constructed Foo that logs hello
Foo.prototype.hello = function(){
console.log("Hello "+this.bar+" :)");
//returns this for chaining
return this;
};
//more extensions, this one changes this.bar's value
Foo.prototype.setBar = function(arg){
//accesses the current Foo instance's .bar property
this.bar = arg;
//returns this for chianing
return this;
};
//should be seeing a pattern
Foo.prototype.goodbye = function(){
console.log("Bye "+this.bar+" :(");
return this;
};
var foo = Foo(42);
//console.log(bar); // ERROR
console.log(foo.bar); // 42
foo.hello(); //Hello 42 :)
foo.hello().setBar(9001).goodbye(); //Hello 42 :) Bye 9001 :(
Foo(12).hello(); //Hello 12 :)
While I don't have anything against that style, I would not personally use it just to be consistent. Sure, I can make all my constructors like this but it would seem like a lot more code to write.
If I'm worried about accidentally invoking a constructor without new
, I would rather use JSHint to warn me about it. See http://www.jshint.com/docs/options/#newcap.