Using Object.create instead of new
With only one level of inheritance, your example may not let you see the real benefits of Object.create
.
This methods allows you to easily implement differential inheritance, where objects can directly inherit from other objects.
On your userB
example, I don't think that your init
method should be public or even exist, if you call again this method on an existing object instance, the id
and name
properties will change.
Object.create
lets you initialize object properties using its second argument, e.g.:
var userB = {
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB, {
'id' : {
value: MY_GLOBAL.nextId(),
enumerable:true // writable:false, configurable(deletable):false by default
},
'name': {
value: 'Bob',
enumerable: true
}
});
As you can see, the properties can be initialized on the second argument of Object.create
, with an object literal using a syntax similar to the used by the Object.defineProperties
and Object.defineProperty
methods.
It lets you set the property attributes (enumerable
, writable
, or configurable
), which can be really useful.
Is there any reason to use Object.create() or new in JavaScript?
So far, if you want to create an object, you can only use literals:
var obj = {};
or the Object
constructor.
var obj = Object();
But none of these methods let you specify the prototype of the created object.
This is what you can do with Object.create
now. It lets you create a new object and sets the first argument as prototype of the new object. In addition, it allows you to set properties of the new object provided as second argument.
It is similar to doing something like this (without the second argument):
function create(proto) {
var Constr = function(){};
Constr.prototype = proto;
return new Constr();
}
So if you are using a construct similar to this, this when you wanted to use Object.create
.
It is not a replacement for new
. It is more an addition to make creating single objects which should inherit from another object simpler.
Example:
I have an object a
:
var a = {
someFunction: function() {}
};
and I want b
to extend this object. Then you can use Object.create
:
b = Object.create(a);
b.someOtherFunction = function(){};
Whenever you have a constructor function, but you only instantiate one object from it, you might be able to replace this with Object.create
.
There is general rule that applies. It depends very much on what the constructor function is doing and how you inherit from other objects, etc.
Object.create vs. new (Class or constructor function)
The key difference between Object.create()
and the new
operator is that, while they both create an object with a prototype chain derived from the prototype object passed, only the new
operator invokes the constructor with the newly created object applied as this
, while Object.create()
does not.
Here's a couple demonstrations of the effects of this difference:
const a = new Array();
const b = Object.create(Array.prototype);
console.log(Array.isArray(a));
console.log(Array.isArray(b));
const c = new Map();
const d = Object.create(Map.prototype);
console.log(c.set('foo', 'bar'));
console.log(d.set('foo', 'bar'));
Understanding the difference between Object.create() and new SomeFunction()
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.
Understanding prototype object creation with 'Object.create()' instead of 'new' keyword
JavaScript is a prototype-based language.
It means that it don't use the class keyword as in other languages. Instead JavaScript use functions as classes.
In your example the data variable can be assimilated to a class:
var Data = function() { ... }
To create an instance of this class we use the new keyword assigning the result of type object to a variable.
var data = new Data()
Since ECMA Script 6 we can use the instantiation method Object.create()
that create an uninitiated object with the specified prototype object and properties. It takes in argument the object which should be the prototype of the newly-created object. (It also copy the constructor)
So the following lines are a way to make Metadata extending the Backend object and keeps its own constructor:
// Metadata extends Backend
Metadata.prototype = Object.create(Backend.prototype);
Metadata.prototype.constructor = Metadata;
But this code is not exactly equivalent to Metadata.prototype = new Backend();
. See this example:
//Base class
var Backend = function(){ this.publicProperty='SomeValue'; }
//Extension class 1
var Metadata1 = function() { }
Metadata1.prototype = Object.create(Backend.prototype);
Metadata1.prototype.constructor = Metadata1;
//Extension class 2
var Metadata2 = function() { }
Metadata2.prototype = new Backend();
/*
* Then the results are different (see code snippet at the end of this post)
*/
//result1 = 'undefined'
var data1 = new Metadata1();
var result1 = data1.publicProperty;
//result2 = 'SomeValue'
var data2 = new Metadata2();
var result2 = data2.publicProperty;
In fact both are very similar, the main difference is that new
keyword actually runs constructor code, whereas Object.create
will not execute code.
One other difference is that with Object.create
you can create an object that doesn't inherit from anything (Object.create(null)
).
Whereas if you do Metadata.prototype = null
the newly created object will inherit from Object.prototype
Note: In some older browser (IE8 and below) you can use this equivalent code to Object.create
:
Object.create = function(o){
function F(){}
F.prototype=o;
return new F();
}
Here is the working code snippet that shows the differences between the two approach
//Base classvar Backend = function(){ this.publicProperty='SomeValue'; }
//Extension class 1var Metadata1 = function() { }Metadata1.prototype = Object.create(Backend.prototype);Metadata1.prototype.constructor = Metadata1;
//Extension class 2var Metadata2 = function() { }Metadata2.prototype = new Backend();
//result: 'undefined'var data1 = new Metadata1();$("#result1").text("result1: " + (typeof data1.publicProperty=='undefined' ? 'undefined' : data1.publicProperty));
//result: 'SomeValue'var data2 = new Metadata2();$("#result2").text("result2: " + (typeof data2.publicProperty=='undefined' ? 'undefined' : data2.publicProperty));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><div id="result1"></div><div id="result2"></div>
What is a practical advantage of Object.create over Constructor function?
Calling a constructor function:
const child = new Human();
is (nearly) the same as:
const child = Object.create(Human.prototype);
Human.call(child);
therefore I would not see Object.create
as a language feature, but rather as a way to understand prototypal inheritance in JS.
There are very very limited usecases for prototype chains without constructors. One example would be the deserialization of a Human
:
const serialized = JSON.stringify(child); // Human inheritance gets lost, its a plain object now
const child2 = Object.assign(Object.create(Human.prototype), JSON.parse(serialized));
Related Topics
How to Get the Non-Enumerable Inherited Property Names of an Object
How to Decode a String with Escaped Unicode
Open a New Tab in the Background
Using Jquery's Ajax Method to Retrieve Images as a Blob
How to Getelementbyclass Instead of Getelementbyid with JavaScript
What Is the Meaning of the 'G' Flag in Regular Expressions
JavaScript Document.Getelementsbyclassname Compatibility with Ie
How to Sort Array Inside Collection Record in Mongodb
How to Render an Array of Objects in React
JavaScript Filter Array of Objects
Event Handlers Inside a JavaScript Loop - Need a Closure
Get Global Variable Dynamically by Name String in JavaScript
Display Posts in Descending Posted Order
What Do Square Brackets Around a Property Name in an Object Literal Mean
Is There a Better Way to Do Optional Function Parameters in JavaScript