Object.create in JavaScript

  1. Classical inheritance with Object.create()
  2. Polyfill

The Object.create() method was introduced in ES5. It creates a new object, using its first argument as the prototype of that object:

1
Object.create(proto, [propertiesObject])

The first argument could only an object or null, otherwise a TypeError will be thrown.

1
2
3
4
5
6
7
8
9
10
var plainObj = {  prop1: 'prop1 value' };
var fn = function(x) {
return x * 2;
};

var obj1 = Object.create(plainObj); // create a normal object
obj1.prop1; // 'prop1 value'
var obj2 = Object.create(null); // create a 'null' object
var obj3 = Object.create(fn); // create a 'function' object
var obj4 = Object.create(undefined); // TypeError was thrown

You can pass null to create a new object that does not have a prototype, in this case the newly created object will not inherit anything, not event basic methods like toString():

1
2
3
var obj = Object.create(null); // create a 'null' object
obj.toString(); // Uncaught TypeError: obj.toString is not a function
obj.valueOf(); // Uncaught TypeError: obj.valueOf is not a function

If you want to create an ordinary empty object, pass Object.prototype or {}:

1
2
3
4
5
var obj1 = Object.create({});
var obj2 = Object.create(Object.prototype); // obj2 is like {} or new Object().

console.log(obj1.toString()); // [object Object]
console.log(obj2.toString()); // [object Object]

Object.create() also takes an optional second argument that describes the properties of the new object. These properties correspond to the second argument of Object.defineProperties().

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Example where we create an object with a couple of
// sample properties. (Note that the second parameter
// maps keys to *property descriptors*.)
var o = Object.create(Object.prototype, {
// foo is a regular 'value property'
foo: {
writable: true,
configurable: true,
value: 'hello'
},
// bar is a getter-and-setter (accessor) property
bar: {
configurable: false,
get: function() { return 10; },
set: function(value) {
console.log('Setting `o.bar` to', value);
}
/* // with ES2015 Accessors our code can look like this
get() { return 10; },
set(value) {
console.log('Setting `o.bar` to', value);
} */
}
});

Classical inheritance with Object.create()

Below is an example of how to use Object.create() to achieve classical inheritance. This is for a single inheritance, which is all that JavaScript supports.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// Shape - superclass
function Shape() {
this.x = 0;
this.y = 0;
}

// superclass method
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved.');
};

// Rectangle - subclass
function Rectangle() {
Shape.call(this); // call super constructor.
}

// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);

//If you don't set Rectangle.prototype.constructor to Rectangle,
//it will take the prototype.constructor of Shape (parent).
//To avoid that, we set the prototype.constructor to Rectangle (child).
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?', rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?', rect instanceof Shape); // true
rect.move(1, 1); // Outputs, 'Shape moved.'

If you wish to inherit from multiple objects, then mixins are a possibility.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function MyClass() {
SuperClass.call(this);
OtherSuperClass.call(this);
}

// inherit one class
MyClass.prototype = Object.create(SuperClass.prototype);
// mixin another
Object.assign(MyClass.prototype, OtherSuperClass.prototype);
// re-assign constructor
MyClass.prototype.constructor = MyClass;

MyClass.prototype.myMethod = function() {
// do something
};

Object.assign() copies properties from the OtherSuperClass prototype to the MyClass prototype, making them available to all instances of MyClass. Object.assign() was introduced with ES2015 and can be polyfilled. If support for older browsers is necessary, jQuery.extend() or _.assign() can be used.

Polyfill

This polyfill covers the main use case, which is creating a new object for which the prototype has been chosen but doesn’t take the second argument into account.

Note that while the setting of null as [[Prototype]] is supported in the real ES5 Object.create, this polyfill cannot support it due to a limitation inherent in versions of ECMAScript lower than 5.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 if (typeof Object.create !== "function") {
Object.create = function (proto, propertiesObject) {
if (typeof proto !== 'object' && typeof proto !== 'function') {
throw new TypeError('Object prototype may only be an Object: ' + proto);
} else if (proto === null) {
throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.");
}

if (typeof propertiesObject != 'undefined') {
throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");
}

function F() {}
F.prototype = proto;

return new F();
};
}

Ref:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create