Instance property vs Prototype property [duplicate] - javascript

This question already has answers here:
Use of 'prototype' vs. 'this' in JavaScript?
(15 answers)
Closed last month.
In the below code,
function Person(first, last, age) {
this.firstName = first;
this.lastName = last;
this.age = age;
}
Person.prototype.planet = "Earth";
p1 = new Person("David", "Beckham", 39);
p2 = new Person("Lionel", "Messi", 30);
If multiple instances p1 p2 are created using constructor Person, then
How do I understand the difference about the property planet with property age? What difference it would make by adding property planet as this.planet in the constructor Person?
Note: Understanding prototype property

Consider situation when in the fututre we are going to change prototype property that is shared by all instances
function Person(first, last, age) {
this.firstName = first;
this.lastName = last;
this.age = age;
}
Person.prototype.planet = "Earth";
p1 = new Person("David", "Beckham", 39);
p2 = new Person("Lionel", "Messi", 30);
console.log(p1.planet) // Earth
Person.prototype.planet = "Mars"
console.log(p1.planet) // Mars
console.log(p1.planet === p2.planet) // true
Changing one property on prototype will change it in all instances

A prototype property will be part of any object created from the so-called prototype, and this includes prototype chain.
A instance property will be part of the whole instance, and in your case, it will part of any instance because you're adding it within the constructor function:
function A() {
this.x = 11;
}
var instance = new A();
instance.x = 11;
Both above cases are adding the property to the own object rather than in the prototype.
Furthermore, adding properties to the prototype has a side effect:
function A() {}
A.prototype.x = 11;
function B() {}
B.prototype = Object.create(A.prototype);
var instanceA = new A();
var instanceB = new B();
A.prototype.x = 12;
// Both "x" will hold 12
alert(instanceA.x);
alert(instanceB.x);
Learn more about prototype chain on MDN.
About some OP comment
So, In java terminology, age is an instance member and planet is a
static member. To define a static member, we use prototype property,
am I correct? –
This is a wrong statement.
Prototype properties aren't static, since prototypes are regular objects. It's just JavaScript uses prototype chain to implement inheritance and it relies in a standard property called prototype.
In JavaScript there're no statics. When you access any property, JavaScript's runtime will look for it through the prototype chain:
function A() {};
A.prototype.x = 11;
function B() {};
B.prototype = Object.create(A.prototype);
function C() {};
C.prototype = Object.create(B.prototype);
var instanceC = new C();
var x = instanceC.x;
// Once you request a property "x", the runtime will do the following process:
// 1) Is "x" in the own object? No, then 2)
// 2) Is "x" in current object's prototype? No, then 3)
// 3) Is "x" in the parent prototype? No, then 4)
// 4) And so on, until it reaches the top-level prototype, and if this has no
// "x" property, then runtime will return "undefined"

It's actually memory usage. Here are some images I have created depicting each problem.
In the image below, each instance of person is linked to the same prototype object. This saves memory if multiple instances are created pointing to the same object. However, if you change 'Earth' to 'Mars' every instance will have the same change.
In the image below each instance will point to a completely different property linked specifically to that instance. If you believe a specific planet can change names, you should do this.. otherwise use prototype because this will use more resources.

Related

Javascript Do object literals have prototype property? [duplicate]

This question already has answers here:
__proto__ VS. prototype in JavaScript
(34 answers)
Closed 2 years ago.
When understanding about the 3 broad type of objects in Javascript i.e. Literal, Function objects and Objects from functions,
I had read somewhere that literal objects do not have prototype property like function objects (or constructors).
Would that be a true statement ?
Reason I am asking this is since we can do;
var person = {
fn: 'ABC'
}
person.__proto__ = someObj;
Not sure if this setting using "proto" is really allowed across all browsers, which is why the statement is not true ?
Also is the same statement true for "objects from functions" ? i.e. when we do "new SomeFunctionObject()"
I had read somewhere that literal objects do not have prototype property like function objects (or constructors).
This sounds like it's referring to the property named .prototype, which is true. A function and a class will automatically receive a .prototype property, which contains one property (constructor, pointing to the class/function itself) and inheriting from Object.prototype.
The statement in your question is true. Only callable class-like objects - classes and functions - automatically receive these sorts of properties. Other objects do not:
class Foo {
}
function Foo2() {
}
const obj = {};
console.log(
Foo.prototype,
Foo2.prototype,
obj.prototype
);
Regarding the code in your question, using __proto__ is permitted, but it's deprecated. As MDN says:
Warning: While Object.prototype.__proto__ is supported today in most browsers, its existence and exact behavior has only been standardized in the ECMAScript 2015 specification as a legacy feature to ensure compatibility for web browsers. For better support, it is recommended that Object.getPrototypeOf() be used instead.
Object.getPrototypeOf should be preferred nowdays.
i.e. when we do "new SomeFunctionObject()"
When you create an instance with new, the internal prototype of the new instance will (usually) be same object as the .prototype property of the constructor. That is, with the following code:
class Foo {
// anything
}
const f = new Foo();
the internal prototype of the f instance will be the same object as Foo.prototype.
class Foo {
// anything
}
const f = new Foo();
console.log(
Object.getPrototypeOf(f) === Foo.prototype,
f.__proto__ === Foo.prototype,
);
The only time where the internal prototype of an instance will not be the same as the constructor's .prototype would be when the constructor explicitly returns an object, which is somewhat unusual.
class Foo {
constructor() {
return {};
}
}
const f = new Foo();
console.log(
Object.getPrototypeOf(f) === Foo.prototype,
f.__proto__ === Foo.prototype,
);
functions have a prototype property, which inherits from Object.
function Person(last, first, middle){
// constructors allow private variables that can be shared across methods without the use of `this.` - API developers may accidentally access properties meant to be private in classes, so use constructors
const proto = Person.prototype;
if(last !== undefined){
this.last = last; this.first = first; this.middle = middle;
}
this.getFullName = (lastFirst = false)=>{
const m = this.middle ? ' '+this.middle : ''
if(lastFirst){
return this.last+', '+this.first+m;
}
return this.first+m+' '+this.last;
}
this.setFullName = (last, first, middle)=>{
proto.last = this.last = last; proto.first = this.first = first;
proto.middle = this.middle = middle;
return this;
}
}
console.log(typeof Person);
const bob = new Person('Smith', 'Bob', 'Gene');
console.log(bob.getFullName());
const james = new Person('Brown', 'James');
console.log(james.getFullName(true));
bob.setFullName('Static', 'Method', 'like');
const person = new Person;
console.log(person.getFullName()+' -- sort of');
console.log(typeof person);
Note that a new instance of a constructor returns a new Object literal.
You can set prototype using this:
Object.setPrototypeOf(obj, prototype)
You can also read docs here.
If you explicitly assign a value to an object's proto, of course now this object has prototype property. When you just assign a value to an object, currently it has no prototype.This property has some problems on compatibility across browsers.
An object built by new Con() certainly has prototype property natively.

Clarifications on prototypal inheritance

I have a prototypal inheritance like below where Student extends Guru. I have three questions, can someone clarify the same.
function Guru(name){
this.name = name;
}
Guru.prototype.copy = function(){
return this.constructor(this.name);
}
function Student(name){
Guru.call(this)
this.name = name;
}
Student.prototype = Object.create(Guru.prototype);
Student.prototype.constructor = Student;
var stu = new Student("John Cena");
console.log(stu.constructor);
console.log(stu.__proto__);
Why should we avoid Student.prototype = new Guru();
What is the difference between these two:
console.log(stu.constructor);
console.log(stu.__proto__);
Prints the below:
[Function: Guru]
Guru { constructor: [Function: Student] }
Difference between constructor.prototype and prototype.constructor? Do we have constructor.prototype in javascript?
Why should we avoid Student.prototype = new Guru()?
Because Guru constructor expects an instance, not a subclass. Properties created in that constructor should be assigned directly to the instance.
In your case it doesn't matter much, but imagine this:
function C1() { this.o = []; }
function C2() {}
C2.prototype = new C1();
var c1a = new C1(), c1b = new C1(),
c2a = new C2(), c2b = new C2();
c1a.o.push(123);
c2a.o.push(456);
c1b.o; // [] -- The property is NOT shared among C1 instances
c2b.o; // [456] -- The property is shared among all Sub instances
What is the difference between stu.constructor and stu.__proto__?
When you create the Student constructor, it receives automatically a prototype with a constructor property which points back to Student.
Instead , __proto__ is a getter which returns the [[Prototype]] of an object. Note this is not much standard (it's only defined in an annex for browsers), you should use Object.getPrototypeOf instead.
Therefore, stu.constructor (inherited from Student.prototype) is Student. And stu.__proto__ (inherited from Object.prototype) is Student.prototype.
Difference between constructor.prototype and prototype.constructor?
Using constructor.prototype on a prototype is pointless because it gives the same prototype (assuming it has not been altered).
Using constructor.prototype on a instance gives the prototype it inherits from (assuming it is not shadowed nor has been altered).
Using prototype.constructor on a constructor is pointless because it gives the same constructor (assuming it has not been altered).

javascript property of value type in prototype

My understanding is all objects of the same type will share the same prototype. So change to the prototype will reflect on every objects. But it seems not the case for property of value type. How is this kind of property stored?
function Person() {
}
Person.prototype.name = "John";
var p1 = new Person();
p1.name = "Luke";
var p2 = new Person();
p2.name = "Mary";
console.log(p1.name); // Luke instead of Mary
console.log(p2.name); // Mary
In case I want to implement a object count of the same type. What's the best way to do it? In other OO language, you normally just use a static member to do it.
Prototype property access is asymmetric.
When you get a property - if the object does not have it, it will fetch it from the prototype. This is specified as:
Let proto be the value of the [[Prototype]] internal property of O.
If proto is null, return undefined.
Return the result of calling the [[GetProperty]] internal method of proto with argument P.
When you set a property - you always set it on the object and not the prototype. As specified here.
To illutstrate:
var proto = {x:4};
var child = Object.create(proto); // create object with prototype set to `proto`
child.x; // 4, fetched from prototype
child.x = 10;
child.x; // 10, fetched from child
proto.x; // 4, setting on child did not change the prototype
Object.getPrototypeOf(child).x = 6; // you can get around it, and set on the proto.
You can read more about it, and why it works this way in Steve Yegge's excellent "the universal design pattern".
When you try to retrieve a property, the object is interrogated to see if it has its own defined. If it doesn't, its constructor's prototype is checked. This happens all the way up the prototype chain until a value is found.
prototype chain explanation
Here's an example.
// Person constructor.
var Person = function (name) {
if (name) {
this.name = name;
}
};
// method to print the name in the console
Person.prototype.sayName = function () {
console.log(this.name);
}
// create two people with names
var person1 = new Person('Nicholas');
var person2 = new Person('Greg');
person1.sayName();
person2.sayName();
// =========================================
// This dude has no name.
var person3 = new Person();
person3.sayName();
// Add a name to the prototype.
// This name is available to all Person instances if they
// don't define their own.
Person.prototype.name = 'Dick';
// These two have their own names.
person1.sayName();
person2.sayName();
// This guy doesn't have his own name, so he
// uses the one from the prototype.
person3.sayName();

Why this behaviour?__proto__ vs prototype?

function Obj1(name){
this.__proto__={
Name:name,
getName:function(){
alert(this.Name);
}
};
}
function Obj2(name){
this.prototype={
Name:name,
getName:function(){
alert(this.Name);
};
};
}
x=new Obj1("blue shark");
z=new Obj2("red shark");
x.getName();
z.getName();// error:z.getName() is not a function
What is the difference between the two?Some say prototype is used for constructor functions only but in this case it doesn't work.... instead the __proto__ work why?
__proto__ (which is not standard (but might be soon))) sets an object's prototype.
.prototype sets the prototype of objects created by invoking the function it was set on as a constructor using new
Also worth mentioning is Object.create
Here are examples:
Pseudo-classical with .prototype:
function Car(){
this.x = 15;
}
Car.prototype.y = 10;
var g = new Car();
g.y; // this is 10;
Using __proto__ (don't use this!):
var g = {x:15};
g.__proto__ = {y:10};
g.y; // this is 10;
This way is correct, and does not use constructors with new:
var g = Object.create({y:10}); //creates x with prototype {y:10}
g.x = 15;
g.y; // this is 10
Here is an interesting tutorial on MDN covering these.
Only functions has the property prototype.
You need to set the prototype on the function self.
function Obj2(name){
this.name = name;
}
Obj2.prototype={
getName:function(){
alert(this.Name);
}
};
__proto__ is not a standard property.
Anyway every object created by new will get a prototype from the .prototype member of the constructor (a function). Note that the prototype member has no name, you cannot access it directly, you need Object.getPrototypeOf(x).
If you want to create an object with a given prototype the code is Object.create(proto) that is more or less equivalent to
function makeObjectWithPrototype(x) {
function makeit() { }
makeit.prototype = x;
return new makeit();
}

Using "Object.create" instead of "new"

Javascript 1.9.3 / ECMAScript 5 introduces Object.create, which Douglas Crockford amongst others has been advocating for a long time. How do I replace new in the code below with Object.create?
var UserA = function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
}
UserA.prototype.sayHello = function() {
console.log('Hello '+ this.name);
}
var bob = new UserA('bob');
bob.sayHello();
(Assume MY_GLOBAL.nextId exists).
The best I can come up with is:
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB);
bob.init('Bob');
bob.sayHello();
There doesn't seem to be any advantage, so I think I'm not getting it. I'm probably being too neo-classical. How should I use Object.create to create user 'bob'?
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.
There is really no advantage in using Object.create(...) over new object.
Those advocating this method generally state rather ambiguous advantages: "scalability", or "more natural to JavaScript" etc.
However, I have yet to see a concrete example that shows that Object.create has any advantages over using new. On the contrary there are known problems with it. Sam Elsamman describes what happens when there are nested objects and Object.create(...) is used:
var Animal = {
traits: {},
}
var lion = Object.create(Animal);
lion.traits.legs = 4;
var bird = Object.create(Animal);
bird.traits.legs = 2;
alert(lion.traits.legs) // shows 2!!!
This occurs because Object.create(...) advocates a practice where data is used to create new objects; here the Animal datum becomes part of the prototype of lion and bird, and causes problems as it is shared. When using new the prototypal inheritance is explicit:
function Animal() {
this.traits = {};
}
function Lion() { }
Lion.prototype = new Animal();
function Bird() { }
Bird.prototype = new Animal();
var lion = new Lion();
lion.traits.legs = 4;
var bird = new Bird();
bird.traits.legs = 2;
alert(lion.traits.legs) // now shows 4
Regarding, the optional property attributes that are passed into Object.create(...), these can be added using Object.defineProperties(...).
Object.create is not yet standard on several browsers, for example IE8, Opera v11.5, Konq 4.3 do not have it. You can use Douglas Crockford's version of Object.create for those browsers but this doesn't include the second 'initialisation object' parameter used in CMS's answer.
For cross browser code one way to get object initialisation in the meantime is to customise Crockford's Object.create. Here is one method:-
Object.build = function(o) {
var initArgs = Array.prototype.slice.call(arguments,1)
function F() {
if((typeof o.init === 'function') && initArgs.length) {
o.init.apply(this,initArgs)
}
}
F.prototype = o
return new F()
}
This maintains Crockford prototypal inheritance, and also checks for any init method in the object, then runs it with your parameter(s), like say new man('John','Smith'). Your code then becomes:-
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}} // For example
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.build(userB, 'Bob'); // Different from your code
bob.sayHello();
So bob inherits the sayHello method and now has own properties id=1 and name='Bob'. These properties are both writable and enumerable of course. This is also a much simpler way to initialise than for ECMA Object.create especially if you aren't concerned about the writable, enumerable and configurable attributes.
For initialisation without an init method the following Crockford mod could be used:-
Object.gen = function(o) {
var makeArgs = arguments
function F() {
var prop, i=1, arg, val
for(prop in o) {
if(!o.hasOwnProperty(prop)) continue
val = o[prop]
arg = makeArgs[i++]
if(typeof arg === 'undefined') break
this[prop] = arg
}
}
F.prototype = o
return new F()
}
This fills the userB own properties, in the order they are defined, using the Object.gen parameters from left to right after the userB parameter. It uses the for(prop in o) loop so, by ECMA standards, the order of property enumeration cannot be guaranteed the same as the order of property definition. However, several code examples tested on (4) major browsers show they are the same, provided the hasOwnProperty filter is used, and sometimes even if not.
MY_GLOBAL = {i: 1, nextId: function(){return this.i++}}; // For example
var userB = {
name: null,
id: null,
sayHello: function() {
console.log('Hello '+ this.name);
}
}
var bob = Object.gen(userB, 'Bob', MY_GLOBAL.nextId());
Somewhat simpler I would say than Object.build since userB does not need an init method. Also userB is not specifically a constructor but looks like a normal singleton object. So with this method you can construct and initialise from normal plain objects.
TL;DR:
new Computer() will invoke the constructor function Computer(){} for one time, while Object.create(Computer.prototype) won't.
All the advantages are based on this point.
Sidenote about performance: Constructor invoking like new Computer() is heavily optimized by the engine, so it may be even faster than Object.create.
You could make the init method return this, and then chain the calls together, like this:
var userB = {
init: function(nameParam) {
this.id = MY_GLOBAL.nextId();
this.name = nameParam;
return this;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
var bob = Object.create(userB).init('Bob');
Another possible usage of Object.create is to clone immutable objects in a cheap and effective way.
var anObj = {
a: "test",
b: "jest"
};
var bObj = Object.create(anObj);
bObj.b = "gone"; // replace an existing (by masking prototype)
bObj.c = "brand"; // add a new to demonstrate it is actually a new obj
// now bObj is {a: test, b: gone, c: brand}
Notes: The above snippet creates a clone of an source object (aka not a reference, as in cObj = aObj). It benefits over the copy-properties method (see 1), in that it does not copy object member properties. Rather it creates another -destination- object with it's prototype set on the source object. Moreover when properties are modified on the dest object, they are created "on the fly", masking the prototype's (src's) properties.This constitutes a fast an effective way of cloning immutable objects.
The caveat here is that this applies to source objects that should not be modified after creation (immutable). If the source object is modified after creation, all the clone's unmasked properties will be modified, too.
Fiddle here(http://jsfiddle.net/y5b5q/1/) (needs Object.create capable browser).
I think the main point in question - is to understand difference between new and Object.create approaches. Accordingly to this answer and to this video new keyword does next things:
Creates new object.
Links new object to constructor function (prototype).
Makes this variable point to the new object.
Executes constructor function using the new object and implicit perform return this;
Assigns constructor function name to new object's property constructor.
Object.create performs only 1st and 2nd steps!!!
In code example provided in question it isn't big deal, but in next example it is:
var onlineUsers = [];
function SiteMember(name) {
this.name = name;
onlineUsers.push(name);
}
SiteMember.prototype.getName = function() {
return this.name;
}
function Guest(name) {
SiteMember.call(this, name);
}
Guest.prototype = new SiteMember();
var g = new Guest('James');
console.log(onlineUsers);
As side effect result will be:
[ undefined, 'James' ]
because of Guest.prototype = new SiteMember();
But we don't need to execute parent constructor method, we need only make method getName to be available in Guest.
Hence we have to use Object.create.
If replace Guest.prototype = new SiteMember();
to Guest.prototype = Object.create(SiteMember.prototype); result be:
[ 'James' ]
Sometimes you cannot create an object with NEW but are still able to invoke the CREATE method.
For example: if you want to define a Custom Element it must derive from HTMLElement.
proto = new HTMLElement //fail :(
proto = Object.create( HTMLElement.prototype ) //OK :)
document.registerElement( "custom-element", { prototype: proto } )
The advantage is that Object.create is typically slower than new on most browsers
In this jsperf example, in a Chromium, browser new is 30 times as fast as Object.create(obj) although both are pretty fast. This is all pretty strange because new does more things (like invoking a constructor) where Object.create should be just creating a new Object with the passed in object as a prototype (secret link in Crockford-speak)
Perhaps the browsers have not caught up in making Object.create more efficient (perhaps they are basing it on new under the covers ... even in native code)
Summary:
Object.create() is a Javascript function which takes 2 arguments and returns a new object.
The first argument is an object which will be the prototype of the newly created object
The second argument is an object which will be the properties of the newly created object
Example:
const proto = {
talk : () => console.log('hi')
}
const props = {
age: {
writable: true,
configurable: true,
value: 26
}
}
let Person = Object.create(proto, props)
console.log(Person.age);
Person.talk();
Practical applications:
The main advantage of creating an object in this manner is that the prototype can be explicitly defined. When using an object literal, or the new keyword you have no control over this (however, you can overwrite them of course).
If we want to have a prototype The new keyword invokes a constructor function. With Object.create() there is no need for invoking or even declaring a constructor function.
It can Basically be a helpful tool when you want create objects in a very dynamic manner. We can make an object factory function which creates objects with different prototypes depending on the arguments received.
You have to make a custom Object.create() function. One that addresses Crockfords concerns and also calls your init function.
This will work:
var userBPrototype = {
init: function(nameParam) {
this.name = nameParam;
},
sayHello: function() {
console.log('Hello '+ this.name);
}
};
function UserB(name) {
function F() {};
F.prototype = userBPrototype;
var f = new F;
f.init(name);
return f;
}
var bob = UserB('bob');
bob.sayHello();
Here UserB is like Object.create, but adjusted for our needs.
If you want, you can also call:
var bob = new UserB('bob');
While Douglas Crockford used to be a zealous advocate of Object.create() and he is basically the reason why this construct actually is in javascript, he no longer has this opinion.
He stopped using Object.create, because he stopped using this keyword altogether as it causes too much trouble. For example, if you are not careful it can easily point to the global object, which can have really bad consequences. And he claims that without using this Object.create does not make sense anymore.
You can check this video from 2014 where he talks at Nordic.js:
https://www.youtube.com/watch?v=PSGEjv3Tqo0
new and Object.create serve different purposes. new is intended to create a new instance of an object type. Object.create is intended to simply create a new object and set its prototype. Why is this useful? To implement inheritance without accessing the __proto__ property. An object instance's prototype referred to as [[Prototype]] is an internal property of the virtual machine and is not intended to be directly accessed. The only reason it is actually possible to directly access [[Prototype]] as the __proto__ property is because it has always been a de-facto standard of every major virtual machine's implementation of ECMAScript, and at this point removing it would break a lot of existing code.
In response to the answer above by 7ochem, objects should absolutely never have their prototype set to the result of a new statement, not only because there's no point calling the same prototype constructor multiple times but also because two instances of the same class can end up with different behavior if one's prototype is modified after being created. Both examples are simply bad code as a result of misunderstanding and breaking the intended behavior of the prototype inheritance chain.
Instead of accessing __proto__, an instance's prototype should be written to when an it is created with Object.create or afterward with Object.setPrototypeOf, and read with Object.getPrototypeOf or Object.isPrototypeOf.
Also, as the Mozilla documentation of Object.setPrototypeOf points out, it is a bad idea to modify the prototype of an object after it is created for performance reasons, in addition to the fact that modifying an object's prototype after it is created can cause undefined behavior if a given piece of code that accesses it can be executed before OR after the prototype is modified, unless that code is very careful to check the current prototype or not access any property that differs between the two.
Given
const X = function (v) { this.v = v };
X.prototype.whatAmI = 'X';
X.prototype.getWhatIAm = () => this.whatAmI;
X.prototype.getV = () => this.v;
the following VM pseudo-code is equivalent to the statement const x0 = new X(1);:
const x0 = {};
x0.[[Prototype]] = X.prototype;
X.prototype.constructor.call(x0, 1);
Note although the constructor can return any value, the new statement always ignores its return value and returns a reference to the newly created object.
And the following pseudo-code is equivalent to the statement const x1 = Object.create(X.prototype);:
const x0 = {};
x0.[[Prototype]] = X.prototype;
As you can see, the only difference between the two is that Object.create does not execute the constructor, which can actually return any value but simply returns the new object reference this if not otherwise specified.
Now, if we wanted to create a subclass Y with the following definition:
const Y = function(u) { this.u = u; }
Y.prototype.whatAmI = 'Y';
Y.prototype.getU = () => this.u;
Then we can make it inherit from X like this by writing to __proto__:
Y.prototype.__proto__ = X.prototype;
While the same thing could be accomplished without ever writing to __proto__ with:
Y.prototype = Object.create(X.prototype);
Y.prototype.constructor = Y;
In the latter case, it is necessary to set the constructor property of the prototype so that the correct constructor is called by the new Y statement, otherwise new Y will call the function X. If the programmer does want new Y to call X, it would be more properly done in Y's constructor with X.call(this, u)
new Operator
This is used to create object from a constructor function
The new keywords also executes the constructor function
function Car() {
console.log(this) // this points to myCar
this.name = "Honda";
}
var myCar = new Car()
console.log(myCar) // Car {name: "Honda", constructor: Object}
console.log(myCar.name) // Honda
console.log(myCar instanceof Car) // true
console.log(myCar.constructor) // function Car() {}
console.log(myCar.constructor === Car) // true
console.log(typeof myCar) // object
Object.create
You can also use Object.create to create a new object
But, it does not execute the constructor function
Object.create is used to create an object from another object
const Car = {
name: "Honda"
}
var myCar = Object.create(Car)
console.log(myCar) // Object {}
console.log(myCar.name) // Honda
console.log(myCar instanceof Car) // ERROR
console.log(myCar.constructor) // Anonymous function object
console.log(myCar.constructor === Car) // false
console.log(typeof myCar) // object
I prefer a closure approach.
I still use new.
I don't use Object.create.
I don't use this.
I still use new as I like the declarative nature of it.
Consider this for simple inheritance.
window.Quad = (function() {
function Quad() {
const wheels = 4;
const drivingWheels = 2;
let motorSize = 0;
function setMotorSize(_) {
motorSize = _;
}
function getMotorSize() {
return motorSize;
}
function getWheelCount() {
return wheels;
}
function getDrivingWheelCount() {
return drivingWheels;
}
return Object.freeze({
getWheelCount,
getDrivingWheelCount,
getMotorSize,
setMotorSize
});
}
return Object.freeze(Quad);
})();
window.Car4wd = (function() {
function Car4wd() {
const quad = new Quad();
const spareWheels = 1;
const extraDrivingWheels = 2;
function getSpareWheelCount() {
return spareWheels;
}
function getDrivingWheelCount() {
return quad.getDrivingWheelCount() + extraDrivingWheels;
}
return Object.freeze(Object.assign({}, quad, {
getSpareWheelCount,
getDrivingWheelCount
}));
}
return Object.freeze(Car4wd);
})();
let myQuad = new Quad();
let myCar = new Car4wd();
console.log(myQuad.getWheelCount()); // 4
console.log(myQuad.getDrivingWheelCount()); // 2
console.log(myCar.getWheelCount()); // 4
console.log(myCar.getDrivingWheelCount()); // 4 - The overridden method is called
console.log(myCar.getSpareWheelCount()); // 1
Feedback encouraged.

Categories

Resources