Using "Object.Create" Instead of "New"

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



Leave a reply



Submit