Understanding the difference between Object.create() and new SomeFunction()
Very simply said, new X
is Object.create(X.prototype)
with additionally running the constructor
function. (And giving the constructor
the chance to return
the actual object that should be the result of the expression instead of this
.)
That’s it. :)
The rest of the answers are just confusing, because apparently nobody else reads the definition of new either. ;)
The object used in Object.create actually forms the prototype of the new object, where as in the new Function() form the declared properties/functions do not form the prototype.
Yes, Object.create
builds an object that inherits directly from the one passed as its first argument.
With constructor functions, the newly created object inherits from the constructor's prototype, e.g.:
var o = new SomeConstructor();
In the above example, o
inherits directly from SomeConstructor.prototype
.
There's a difference here, with Object.create
you can create an object that doesn't inherit from anything, Object.create(null);
, on the other hand, if you set SomeConstructor.prototype = null;
the newly created object will inherit from Object.prototype
.
You cannot create closures with the Object.create syntax as you would with the functional syntax. This is logical given the lexical (vs block) type scope of JavaScript.
Well, you can create closures, e.g. using property descriptors argument:
var o = Object.create({inherited: 1}, {
foo: {
get: (function () { // a closure
var closured = 'foo';
return function () {
return closured+'bar';
};
})()
}
});
o.foo; // "foobar"
Note that I'm talking about the ECMAScript 5th Edition Object.create
method, not the Crockford's shim.
The method is starting to be natively implemented on latest browsers, check this compatibility table.
Here are the steps that happen internally for both calls:
(Hint: the only difference is in step 3)
new Test()
:
- create
new Object()
obj - set
obj.__proto__
toTest.prototype
return Test.call(obj) || obj; // normally obj is returned but constructors in JS can return a value
Object.create( Test.prototype )
- create
new Object()
obj - set
obj.__proto__
toTest.prototype
return obj;
So basically Object.create
doesn't execute the constructor.
Let me try to explain (more on Blog) :
- When you write
Car
constructorvar Car = function(){}
, this is how things are internally: We have one{prototype}
hidden link toFunction.prototype
which is not accessible and oneprototype
link toCar.prototype
which is accessible and has an actualconstructor
ofCar
. Both Function.prototype and Car.prototype have hidden links toObject.prototype
. -
When we want to create two equivalent objects by using the
new
operator andcreate
method then we have to do it like this:Honda = new Car();
andMaruti = Object.create(Car.prototype)
. What is happening?Honda = new Car();
— When you create an object like this then hidden{prototype}
property is pointed toCar.prototype
. So here, the{prototype}
of the Honda object will always beCar.prototype
— we don't have any option to change the{prototype}
property of the object. What if I want to change the prototype of our newly created object?Maruti = Object.create(Car.prototype)
— When you create an object like this you have an extra option to choose your object's{prototype}
property. If you want Car.prototype as the{prototype}
then pass it as a parameter in the function. If you don't want any{prototype}
for your object then you can passnull
like this:Maruti = Object.create(null)
.
Conclusion — By using the method Object.create
you have the freedom to choose your object {prototype}
property. In new Car();
, you don't have that freedom.
Preferred way in OO JavaScript :
Suppose we have two objects a
and b
.
var a = new Object();
var b = new Object();
Now, suppose a
has some methods which b
also wants to access. For that, we require object inheritance (a
should be the prototype of b
only if we want access to those methods). If we check the prototypes of a
and b
then we will find out that they share the prototype Object.prototype
.
Object.prototype.isPrototypeOf(b); //true
a.isPrototypeOf(b); //false (the problem comes into the picture here).
Problem — we want object a
as the prototype of b
, but here we created object b
with the prototype Object.prototype
.
Solution — ECMAScript 5 introduced Object.create()
, to achieve such inheritance easily. If we create object b
like this:
var b = Object.create(a);
then,
a.isPrototypeOf(b);// true (problem solved, you included object a in the prototype chain of object b.)
So, if you are doing object oriented scripting then Object.create()
is very useful for inheritance.
This:
var foo = new Foo();
and
var foo = Object.create(Foo.prototype);
are quite similar. One important difference is that new Foo
actually runs constructor code, whereas Object.create
will not execute code such as
function Foo() {
alert("This constructor does not run with Object.create");
}
Note that if you use the two-parameter version of Object.create()
then you can do much more powerful things.