JavaScript inheritance: Object.create vs new
In your question you have mentioned that Both examples seem to do the same thing
, It's not true at all, because
Your first example
function SomeBaseClass(){...}
SomeBaseClass.prototype = {
doThis : function(){...},
doThat : function(){...}
}
function MyClass(){...}
MyClass.prototype = Object.create(SomeBaseClass.prototype);
In this example, you are just inheriting SomeBaseClass' prototype
but what if you have a property in your SomeBaseClass
like
function SomeBaseClass(){
this.publicProperty='SomeValue';
}
and if you use it like
var obj=new MyClass();
console.log(obj.publicProperty); // undefined
console.log(obj);
The obj
object won't have publicProperty
property like in this example.
Your second example
MyClass.prototype = new SomeBaseClass();
It's executing the constructor
function, making an instance of SomeBaseClass
and inheriting the whole SomeBaseClass
object. So, if you use
var obj=new MyClass();
console.log(obj.publicProperty); // SomeValue
console.log(obj);
In this case its publicProperty
property is also available to the obj
object like in this example.
Since the Object.create
is not available in some old browsers, in that case you can use
if(!Object.create)
{
Object.create=function(o){
function F(){}
F.prototype=o;
return new F();
}
}
Above code just adds Object.create
function if it's not available so you can use Object.create
function and I think the code above describes what Object.create
actually does. Hope it'll help in some way.
What is the real difference between new vs Object.create()
new
can be used only with a function or a class.
When a function is executed asnew User(...)
, it does the following steps:A new empty object is created and assigned to
this
.The function body executes. Usually it modifies
this
, adds new properties to it.If there is no explicit
return
statement, the value ofthis
is returned.
b1obj.key1
isundefined
becauseObject.create
first parameter is an object wich becomes a prototype of created object. In this case it is thea1
function, which doesn't have akey1
property assigned, it only assigneskey1
to itsthis
when called.
b2obj
has thea2
object as its prototype, so it has access to itskey2
property
Suming up: while new
keyword is more often used to create new instances of objects from an existing 'template', Object.create
is more flexible and allows you to work with a prototype, create property descriptors. For example, you can create a shallow copy of object:
let clone = Object.create(Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj));
I suggest you to read this article about new
keyword and this one about Object.create
and other prototype methods.
UPDATE (about the relationship between object and its prototype):
Once you have created a new object, changing its properties does not affect the prototype. For example,
let a2 = {
key2: "some text"
};
let b2 = Object.create(a2);
a2.key2 = "I am a2";
b2.key2 = "I am b2";
alert(a2.key2 + ", " + b2.key2);
will alert I am a2, I am b2
. That's because b2
has its own key2
property. But If it doesn't, JavaScript will look for it in its prototype. You can find a detailed description of the prototype inheritance here
Difference between Object.create(Parent.prototype) vs Object.create(Parent) during prototype inheritance
You usually want to be using Object.create(prototype)
for creating an object from another object and Object.create(Class.protoype)
for creating an object from a function.
Doing Object.create(Class)
will use the function as a template, meaning only the "static" fields will be transferred to the new object. Object.create(Class.protoype)
will use the prototype as the template, thus you will be able to get all fields that were declared using Class.prototype.field
, you can also get the static fields through the constructor, and finally, once the constructor function is run on the new object the fields declared inside the constructor will also be created.
function Foo() { // Only visible by prototype after running constructor this.test = function() {};}Foo.prototype.bar = "Bar"; // Visible by prototypeFoo.fooBar = "FooBar"; // Visible by class
var classFoo = Object.create(Foo);var protoFoo = Object.create(Foo.prototype);
// fooBar is static, so it can be viewd bu classFooconsole.log(classFoo.fooBar); // bar was added to the prototype, cant be viewedconsole.log(classFoo.bar); // test is declared in the constructor, to which there is no pointer from classFooconsole.log(classFoo.test); // this constructor is the base constructor for all classesconsole.log(classFoo.constructor);
// fooBar was added to the constructor, so it cannot be viewed this wayconsole.log(protoFoo.fooBar); // but it can be viewed like thisconsole.log(protoFoo.constructor.fooBar); // this is the Foo function/constructorconsole.log(protoFoo.constructor); // bar is added to the prototype so it can be viewedconsole.log(protoFoo.bar); // test has not been declared yet as the constructor has not been run yetconsole.log(protoFoo.test);// the foo function is run with protoFoo as thisprotoFoo.constructor();// the test function has now been added to protoFooconsole.log(protoFoo.test);
JavaScript inheritance with Object.create()?
Object.create()
is used to inherit objects, not constructors like you're trying to do. It pretty much creates a new object with the old object set as its prototypal parent.
var A = function() { };
A.prototype.x = 10;
A.prototype.say = function() { alert(this.x) };
var a = new A();
a.say(); //alerts 10
var b = Object.create(a);
b.say(); //alerts 10
b.x = 'hello';
b.say(); //alerts 'hello'
And just to make sure b is not just a clone of a,
a.x = 'goodbye';
delete b.x;
b.say(); //alerts 'goodbye'
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.
Prototypal inheritance: Object.create vs Object.assign
We achieve the same result
No, we don't. Bar.prototype
would then not inherit from Foo.prototype
, instead it would have its own properties. Sure, the values from Foo.prototype
would be copied over, but that's just a snapshot of Foo.prototype
from the time Object.assign
was called instead of a live connection.
Related Topics
Executing JavaScript from Python
React - Preventing Form Submission
Why Does Isnan(" ") (String with Spaces) Equal False
How to Break Nested Loops in JavaScript
What Does Arrow Function '() => {}' Mean in JavaScript
Multiple Path Names for a Same Component in React Router
Secure Random Numbers in JavaScript
Detecting Line-Breaks with Jquery
Does Console.Log Invokes Tostring Method of an Object
Es6: Conditional & Dynamic Import Statements
Sanitizing User Input Before Adding It to the Dom in JavaScript
How to Get a JavaScript Object Property Name That Starts with a Number
Why Does an Onclick Property Set with Setattribute Fail to Work in Ie
Puppeteer Page.Evaluate Queryselectorall Return Empty Objects