How Prototypal inheritance works in reverse order - javascript

As you can see below is my code. I have created two objects halogen and balloon and given halogen property of sing and balloon property of read. I am calling halogen.read() it is getting read property but halogen is prototype for balloon but balloon is not prototype of halogen. How js is working under the hood??
const halogen = {
sing: function() {
console.log('I can sing');
}
}
const balloon = new Object(halogen);
balloon.read = function() {
console.log('I can read');
}
halogen.read();

When you call the Object constructor with an argument that isn't null or undefined, it doesn't create a new object (not even when you use new, surprisingly; spec link), it just converts the argument to object if it isn't already an object and returns it. Since halogen already refers to an object, there's no conversion required and you're basically doing balloon = halogen and they both end up referring to the same object.
You probably meant to use Object.create, which creates a new object and assigns the object argument you provide as the new object's prototype:
const halogen = {
sing: function() {
console.log("I can sing");
},
};
const balloon = Object.create(halogen);
balloon.read = function() {
console.log("I can read");
};
console.log(typeof halogen.read); // undefined
console.log(typeof balloon.read); // function
console.log(typeof balloon.sing); // function

Related

Javascript does not call prototype method

I try to override a method and script is:
function wrapper(target) {
target.doABC = function () {
alert('in wrapper');
};
return target;
}
function Model() {
wrapper(this);
}
Model.prototype.doABC = function () {
alert('in Model');
};
var a = new Model();
a.doABC();
The result is 'in wrapper'. I don't know why?
Any JavaScript object has own and inherited properties. Own are those defined directly on the instance and inherited are taken from the prototype object.
When using a property accessor, JavaScript first searches in object's own properties list. If the property is not found, it searches in object's prototype chain.
In your example, the wrapper() method defines on object instance an own property doABC, which is a function that alerts 'in wrapper'. Even if the object has a prototype with the same property doAbc that alerts 'in Model', JavaScript anyway will use the own property.
function wrapper(target) {
// Define an own property "doABC"
target.doABC = function () {
alert('in wrapper');
};
return target;
}
function Model() {
wrapper(this);
}
// Define an inherited property "doABC"
Model.prototype.doABC = function () {
alert('in Model');
};
var a = new Model();
//Use the own property "doABC". The inherited "doABC" is ignored.
a.doABC();
As an addition, the own property can be removed using delete operator. After deletion, the object will use the inherited property.
// delete the own property "doABC"
delete a['doABC'];
// the inherited "doABC" will be used. Alerts "in Model"
a.doABC();
Check the complete working demo.
Let me see if I can explain:
You have two separate versions of doABC here.
Your target.doABC creates a function specific to that instance of your Model and each Model get its own doABC.
Because Model has a doABC, the JavaScript engine has no need to look 'up the chain' for something else, hence it will never look for the Model.prototype.doABC version.
You can see this by adding these lines:
Model.prototype.doXYZ = function () {
alert('in Model');
};
and calling
a.doXYZ();
Since a doesn't have its own doXYZ then, and only then, will it look up the chain and see the method in the prototype.

In Javascript, Why setting prototype on constructor function changes .constructor value on its instance?

function Human(){
this.job = 'code'
}
//Human.prototype = {feeds: 'Pizza'};
var developer = new Human();
console.log(developer.constructor);
Above console logs
function Human() {
this.job = 'code';
}
When i uncomment the line Human.prototype = {feeds: 'Pizza'}; it console logs
function Object() {
[native code]
}
Why setting prototype on constructor function, affects who is the constructor on object created by the constructor?
Another example:
function LivingBeing() {
breathes: 'air';
}
function Human(){
feeds: 'Pizza';
}
//Human.prototype = new LivingBeing();
var developer = new Human();
console.log(developer.constructor);
With commented like it says constructor is Human, when uncommented it says LivingBeing. Why constructor traverses further when something valid found on prototype?
I thought to add one more level to this
function AThing(){
this.say = function(){return 'I am thing';};
}
function LivingBeing() {
breathes: 'air';
}
LivingBeing.prototype = new AThing();
function Human(){
feeds: 'Pizza';
}
Human.prototype = new LivingBeing();
var developer = new Human();
console.log(developer.constructor);
Now its says developer's constructor is AThing. Can i say constructor goes as far as possible in the prototype chain?
developer has no own property named constructor therefore when you're asking for it, it's looked for in the prototype chain. Since the prototype is a plain Object, its constructor is the default object constructor Object().
When you declare a new function like function Human(), JS creates an implicit object and populates prototype and constructor fields as follows:
X = {}
Human.prototype = X
X.constructor = Human
now, when you write dev = new Human, the internal __proto__ property of dev is set to X and dev.constructor resolves to X.constructor, which is Human.
When you uncomment the "pizza" line, the code turns into the following:
Human.prototype = X
X.constructor = Human
pizza = {feeds:'Pizza'}
// pizza.__proto__ = {}
// pizza.constructor = pizza.__proto__.constructor = Object
Human.prototype = pizza
// note that pizza.constructor does NOT change
dev = new Human
// dev.__proto__ = Human.prototype = pizza
dev.constructor
// dev.constructor = dev.__proto__.constructor = pizza.constructor = pizza.__proto__.constructor = Object()
What is a constructor?
Returns a reference to the Object function that created the instance's
prototype. Note that the value of this property is a reference to the
function itself, not a string containing the function's name. The
value is only read-only for primitive values such as 1, true and
"test".
First Case:
The constructor of developer was the function Human(){this.job = "code";}.
Second Case:
Since you are overriding the prototype to object, now the developer is an instance of Object {}.
The Console shows any native global objects, predefined in the implementationof javascript itself as [native code]. That is they don't reveal the implementation.

prototype odd result when changing way to define

When trying to test prototype functionality, I got this odd result:
Here is my first test:
<script>
function Hello() {
}
var a = new Hello();
Hello.prototype.name = "Fred";
alert(a.name);
</script>
And, here's the second one:
<script>
function Hello() {
}
var a = new Hello();
Hello.prototype = {
name : "Fred",
}
alert(a.name);
</script>
I can't understand why the first will return a alert with "Fred" and the second is "undefined" though these mean the same thing?
Could you help me with it?
Thank you.
When you define a function in JavaScript, the interpreter makes a special prototype property available on the function, which points to an object, in case you use that function as a constructor. The [[Prototype]] internal property points to this object when you create a new object using the constructor.
When you replace the prototype property with a new one, you are replacing that reference, and if you do it after you instantiate an object, you will find the prototype object appears to be stale (that object's [[Prototype]] is pointing to the original object that prototype pointed to).
Solutions
Only assign new properties directly on the prototype property.
var constructor = function() { };
constructor.prototype.someMethod = function() { };
Use an extend type function to extend the existing prototype property with your new object (in this example, I used Underscore's extend() function).
var constructor = function() { };
_.extend(constructor.prototype, { someMethod: function() { } });
Make sure after the constructor, assigning the prototype property is the very next step in your program (generally not recommended).
var constructor = function() { };
constructor.prototype = { someMethod: function() { } };
Your ordering is messed up. You need assign the object to the prototype before using the new operator:
function Hello() {
}
Hello.prototype = {
name : "Fred",
}
var a = new Hello();
alert(a.name);​
Demo.
The two code snippets are not actually equal.
In the first script you only override Hello.prototype.name, while in the second script you override the whole content of Hello.prototype.

Why is it impossible to change constructor function from prototype?

I have such example.
function Rabbit() {
var jumps = "yes";
};
var rabbit = new Rabbit();
alert(rabbit.jumps); // undefined
alert(Rabbit.prototype.constructor); // outputs exactly the code of the function Rabbit();
I want to change the code in Rabbit() so that the var jumps becomes public. I do it this way:
Rabbit.prototype.constructor = function Rabbit() {
this.jumps = "no";
};
alert(Rabbit.prototype.constructor); // again outputs the code of function Rabbit() and with new this.jumps = "no";
var rabbit2 = new Rabbit(); // create new object with new constructor
alert(rabbit2.jumps); // but still outputs undefined
Why is it not possible to change the code in constructor function this way?
You cannot change a constructor by reassigning to prototype.constructor
What is happening is that Rabbit.prototype.constructor is a pointer to the original constructor (function Rabbit(){...}), so that users of the 'class' can detect the constructor from an instance. Therefore, when you try to do:
Rabbit.prototype.constructor = function Rabbit() {
this.jumps = "no";
};
You're only going to affect code that relies on prototype.constructor to dynamically instantiate objects from instances.
When you call new X, the JS engine doesn't reference X.prototype.constructor, it uses the X as the constructor function and X.prototype as the newly created object's prototype., ignoring X.prototype.constructor.
A good way to explain this is to implement the new operator ourselves. ( Crockford will be happy, no more new ;)
// `new` emulator
//
// Doesn't reference `.constructor` to show that prototype.constructor is not used
// when istantiating objects a la `new`
function make(ctorFun, argsArray) {
// New instance attached to the prototype but the constructor
// hasn't been called on it.
const newInstance = Object.create(ctorFun.prototype);
ctorFun.apply(newInstance, argsArray);
return newInstance;
}
// If you create a utility function to create from instance, then it uses the
// inherited `constructor` property and your change would affect that.
function makeFromInstance(instance, argsArray) {
return make(instance.constructor, argsArray);
}
function X(jumps) {
this.jumps = jumps;
}
// Flip the constructor, see what it affects
X.prototype.constructor = function(jumps) {
this.jumps = !jumps;
}
const xFromConstructorIsGood = make(X, [true]);
const xFromInstanceIsBad = makeFromInstance(xFromConstructorIsGood, [true]);
console.log({
xFromConstructorIsGood,
xFromInstanceIsBad
});
Inheritance in JS
Libraries that help with JS inheritance implement inheritance and do rely on prototype.constructor with something in the spirit the following:
function extend(base, sub) {
function surrogateCtor() {}
// Copy the prototype from the base to setup inheritance
surrogateCtor.prototype = base.prototype;
sub.prototype = new surrogateCtor();
// The constructor property is set to the base constructor
// with the above trick, let's fix it
sub.prototype.constructor = sub;
}
You can see that in the above code, we have to fix the constructor property because it's sometimes used to create instantiate an object when you only have an instance. but it doesn't affect the actual constructor. See my post about JS inheritance http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html
How to redefine a constructor
If you really want to redefine a constructor, just do
// If Rabbit had any custom properties on it
// (or static properties as some call it), they would not be copied, you'd have to do that manually using getOwnPropertyNames
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames
var oldProto = Rabbit.prototype;
Rabbit = function() {...};
Rabbit.prototype = oldProto;
Note that this would not affect code that had already copied that reference, for example:
const myRefRabbit = Rabbit
This is wonderful workaround creating an object from a literal, not from constructor function.
Firstly, if you want jumps member to be contained in the object, rather than being just a local variable in the constructor then you need this keyword.
function Rabbit() {
this.jumps = "yes";
};
var rabbit = new Rabbit();
alert(rabbit.jumps); // not undefined anymore
And now you can easily now access jumps publicly the way you wanted:
rabbit.jumps = 'no';
alert(rabbit.jumps); // outputs 'no'
But still if you create another Rabbit object it will initially have 'yes' as defined in the constructor, right?
var rabbit2 = new Rabbit();
alert(rabbit.jumps); // outputs 'no' from before
alert(rabbit2.jumps); // outputs 'yes'
What you could do is creating a Rabbit from some default Rabbit Object. The concrete rabbits will always have the default value from default Rabbit object even when you change it on the fly unless you have changed the value in concrete rabbit object (implementation). This is a different than #Juan Mendes's solution which is probably the best but it can open another point of view.
Rabbit = {jumps : 'yes'}; // default object
rabbit = Object.create(Rabbit);
Rabbit.jumps = 'no';
rabbit2 = Object.create(Rabbit);
console.log(rabbit.jumps); // outputs "no" - from default object
console.log(rabbit2.jumps); // outputs "no" - from default object
// but...
rabbit.jumps = 'yes';
Rabbit.jumps = 'unknown';
console.log(rabbit.jumps); // outputs "yes" - from concrete object
console.log(rabbit2.jumps); // outputs "unknown" - from default object
Try the following
function Rabbit() {
this.jumps = "no";
};
var rabbit = new Rabbit();
alert(rabbit.jumps); // Prints "no"

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