I know this is not the recommended way of doing it, but if I declare the following functions, and then invoke them as constructors, what will be the difference (if any) between the resulting objects?
function Something() {
this.foo = "bar";
}
function something2() {
var that = {};
that.foo = "bar";
return that;
}
var x = new Something();
var y = new something2();
var z = something2();
I.e. what will differ between x
, y
and z
here?
Wouldn't something2
be a much better way of writing the constructor, since whether you use new
or not will not affect the result of the function?
BTW should something2
be capitalized here? (I assume not since Crockford is so adamant on the capitalization, for functions will clobber the global namespace...)
In short:
new something2() instanceof something2 === false
Relatedly, if you extend your example to use the prototype property
Something.prototype.method = function () { };
something2.prototype.method = function () { };
you will find that the prototype is not inherited in the latter case:
typeof (new Something()).method === "function"
type (new something2()).method === "undefined"
The real answer is that you are tapping into entirely different underlying machinery. Calling with new
invokes the [[Construct]] mechanism, which involves setting the [[Prototype]] property according to the .prototype
property of the constructor.
But a funny thing happens in steps 8--10 of the [[Construct]] algorithm: after setting up a new, empty object, and then attaching its [[Prototype]], it does a [[Call]] to the actual constructor, using this new empty-plus-prototype object as this
. And then, in step 9, if it turns out that that constructor returned something---it throws away that prototypally-bound, passed-as-this
object that it spent all that time setting up!
Note: you can access an object's [[Prototype]] (which is different from a constructor's .prototype
) with Object.getPrototypeOf
:
Object.getPrototypeOf(new Something()) === Something.prototype // steps 5 & 6
Object.getPrototypeOf(new something2()) === Object.prototype // default
To answer some meta-questions:
something2
, since it is a factory function and not a constructor. If something is capitalized, it is expected to have constructor semantics, e.g. new A() instanceof A
."use strict";
at the top of your files. One of the many nice cleanups of strict mode is that this
defaults to undefined
, not the global object, so e.g. calling a constructor without new
will result in errors the moment the constructor tries to attach properties to undefined
.In the second case, the returned object doesn't inherit anything from the constructor, so there's little point in using it as such.
> var x = new Something();
> var y = new something2();
> var z = something2();
I.e. what will differ between x, y and z here?
x
inherits from Something
, wheres neither y
or z
inherit from something2
.
Wouldn't something2 be a much better way of writing the constructor, since whether you use new or not will not affect the result of the function?
There is no point in calling something2
as a constructor because the object it returns isn't the newly constructed object assigned to its this
that inherits from something2.prototype
, which is what others might expect to get when calling new something2()
.
BTW should something2 be capitalized here? (I assume not since Crockford is so adamant on the capitalization, for functions will clobber the global namespace...)
No, because calling it as a constructor is a bit pointless, so characterising it as one would be misleading.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With