Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding prototype object creation with 'Object.create()' instead of 'new' keyword

I came to a code that contains these lines

var data = function() {
    function Metadata() { /*some initialization here*/ }

    Metadata.prototype = Object.create(Backend.prototype);
    Metadata.prototype.constructor = Metadata;

    return Metadata;
}

I struggle to understand what is actually going on, and how to use the returning object. If I understand it correctly, data will now be an object that should be initialized like this

var d = new data()

But I don't understand the following lines and why Object.create() is used instead of the new keyword:

Metadata.prototype = Object.create(Backend.prototype);
Metadata.prototype.constructor = Metadata;

What do they do? Are they necessary? And what is the difference between Object.create and new ?

like image 989
Karel Bílek Avatar asked May 28 '15 16:05

Karel Bílek


1 Answers

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 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();


//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>
like image 140
Ludovic Feltz Avatar answered Oct 21 '22 20:10

Ludovic Feltz