Probably the least understood part of JavaScript, standing beside the prototype chain.
So the question is: how does...
new dataObj(args);
...actually create an object, and define its prototype chain/constructors/etc?
Best is to show an alternative, to fully understand this keyword.
-
2Sort of related: stackoverflow.com/questions/1646698/…Ivan– Ivan07/19/2011 16:59:48Commented Jul 19, 2011 at 16:59
2 Answers 2
The new
operator uses the internal [[Construct]]
method, and it basically does the following:
- Initializes a new native object
- Sets the internal
[[Prototype]]
of this object, pointing to the Functionprototype
property.- If the function's
prototype
property is not an object (a primitive values, such as a Number, String, Boolean, Undefined or Null),Object.prototype
is used instead.
- If the function's
- After creating the object, it calls the function, providing the object as its
this
value. - If the return value of the called function, is a primitive, the object created internally is returned.
- Otherwise, if an object is returned, the object created internally is lost.
An equivalent implementation of what the new
operator does, can be expressed like this (assuming that the ECMAScript 5 Object.create
method is available):
function NEW(f) {
var obj, ret, proto;
// Check if `f.prototype` is an object, not a primitive
proto = Object(f.prototype) === f.prototype ? f.prototype : Object.prototype;
// Create an object that inherits from `proto`
obj = Object.create(proto);
// Apply the function setting `obj` as the `this` value
ret = f.apply(obj, Array.prototype.slice.call(arguments, 1));
if (Object(ret) === ret) { // the result is an object?
return ret;
}
return obj;
}
// Example usage:
function Foo (arg) {
this.prop = arg;
}
Foo.prototype.inherited = 'baz';
var obj = NEW(Foo, 'bar');
obj.prop; // 'bar'
obj.inherited; // 'baz'
obj instanceof Foo // true
-
Would it be safe to replace Object.create(proto) with > var newObj = {}; newObj.prototype = proto; ?PicoCreator– PicoCreator07/20/2011 01:11:07Commented Jul 20, 2011 at 1:11
-
4@pico.creator: No, the
prototype
property is only meaningful for Function objects, when used as constructors, and using a constructor in my example implementation ofnew
, would have needed to use thenew
operator anyway... The only other way around would be to use the__proto__
property, but it's non-standard and it is being deprecated. See this answer in which I explain the difference between theprototype
property of function objects and the internal[[Prototype]]
property that all objects have forming the prototype chain.Christian C. Salvadó– Christian C. Salvadó07/20/2011 06:37:26Commented Jul 20, 2011 at 6:37 -
The dual usage of the term is certainly confusing. However the answer left out the setting of object constructor; Cause from my experiments, seems like the constructor function is cloned, applied, and added to the result .constructor value.PicoCreator– PicoCreator07/21/2011 07:13:10Commented Jul 21, 2011 at 7:13
-
I'm assuming the
arguments
in the example are supposed to bef
.. or am I missing something?max– max07/08/2015 19:49:32Commented Jul 8, 2015 at 19:49
The expression new C(arg1, arg2)
:
Assuming C is a JavaScript function (otherwise you get an error):
- Creates a new empty object (no properties)
- Sets the prototype of the new object to the value of the
"
prototype
" property ofC
.- Note: The default value of
prototype
for a function is an object (automatically created when the function is declared) with its prototype set toObject.prototype
and aconstructor
property pointing back to the functionC
. - Note: The terminology can be confusing. The property named "prototype" is not the same as the prototype of the object. Only functions have the property named "prototype", but all objects have a prototype.
- Note: The default value of
- Calls the function
C
with 'this
' set to the new object, and with the supplied arguments. - If calling the function
C
returns an object, this object is the result of the expression. Otherwise the newly created object is the result of the expression.
An alternative to new
in ECMAScript 5 would be to use the builtin Object.createObject
method.
new C(arg1, arg2)
would be equivalent to:
var obj = Object.createObject(C.prototype);
C.apply(obj, [arg1, arg2]);
Standard JavaScript does not allow you to explicitly set the prototype of an object, so Object.createObject
cannot be implemented in the language itself. Some implementations does allow it through the non-standard property __proto__. In that case, new C
can be simulated like this:
var obj = {};
obj.__proto__ = C.prototype;
C.apply(obj, [arg1, arg2]);
-
1Note on the point #2: The default value of the
prototype
property of any user defined function, is an object that contains theconstructor
property that refers back to the function itself, and it inherits fromObject.prototype
. This object is initialized when function objects are created. AboutObject.create
, it can be just be partially emulated on ES3, setting the[[Prototype]]
property can be done through a temporary constructor, but yes, it's impossible to emulate completely, see more. Cheers.Christian C. Salvadó– Christian C. Salvadó07/20/2011 07:38:05Commented Jul 20, 2011 at 7:38