I come from a conservative OOP language (JAVA) and dont really understand Javascript inheritance. I am also shaky with the whole Prototype concept but I have seen an example here that answers my need but I dont understand the details and why things are not done differently.
Taking their example, the correct implementation is as follows
function Animal(name) {
this.name = name;
}
// Example method on the Animal object
Animal.prototype.getName = function() {
return this.name;
}
function Mammal(name, hasHair) {
// Use the parent constructor and set the correct `this`
Animal.call(this, name);
this.hasHair = hasHair;
}
// Inherit the Animal prototype
Mammal.prototype = Object.create(Animal.prototype);
// Set the Mammal constructor to 'Mammal'
Mammal.prototype.constructor = Mammal;
I do not understand the purpose of the Object.call() function nor do i understand why Object.create() was used and not simply just Animal.prototype. Also why is the constructor being added in the last line? Is it because it is erased in the step before? And what should I do if I wanted to share code in among all Mammal instances?
Thanks in advance
If you did not call the Mammal.prototype.constructor = Mammal; then the constructor would be Animal() (which is the constructor of Animal.prototype by default)
Using Object.create() means Mammal.prototype is not a reference to Animal.prototype but instead a new object inheriting that prototype.
And using Object.call() ensures the scope is not that of the function calling the method and instead is the scope of the Mammal constructor.
Javascript can not extend classes like Java does. You can only simulate something like that.
Animal.call make sure the animal.this does not point to animal but rather point to Mammal. In short the call() function overwrites #this.
object.create simply creates an instance of an empty function with given object as prototype:
Object.create = function (o) {
function F() {};
F.prototype = o;
return new F();
}
Its only needed when using a child constuctor. If not a simple object will do it as well.
Here is a good advice:
http://javascriptissexy.com/oop-in-javascript-what-you-need-to-know/
Related
AFAIK, JS provides inheriatnce by means of assigning a prototype chain to a newly created object. So, the code below seems to be the correct way to me:
function Animal(name){
this.name = name;
}
Animal.prototype.getName = function(){return this.name;};
function Cat(){
Animal.apply(this, arguments);
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Cat.prototype.sayHi = function(){return 'Hi, my name is '+this.name+', and I am a "'+this.constructor.name+'" instance';};
Is this actually correct? And, I've read, that mutating object's prototype is a slow discouraged operation, that affects all the later calls to it. But here we've just mutated Animal.prototype and Cat.prototype. So, is that bad? If it is how do we deal with it? Or I've misunderstood something about that prototype mutating warning? If so, what does it actually mean?
Is this actually correct?
In that it doesn't contain anything that might be considered poor practice, yes. Whether it's correct in terms of the outcome being what you expected can't be determined.
And, I've read, that mutating object's prototype is a slow discouraged operation,
I have no idea what that means. However, it's not considered good practice to modify objects you don't own, so don't go messing with built–in or host objects (there are many articles on why not, e.g. What's wrong with extending the DOM and Extending builtin natives. Evil or not?).
that affects all the later calls to it.
Modifying a prototype may affect all objects that have it as their [[Prototype]], that's the point of prototype inheritance.
But here we've just mutated Animal.prototype and Cat.prototype. So, is that bad?
Of itself, no. If it achieves the outcome you require, then fine. You're defining the constructor, prototype properties and inheritance scheme, so it's up to you. There might be more efficient or more easily maintained schemes, but that's another topic.
Comment
Complex inheritance schemes are rarely useful in javascript, there just isn't much call for it. Most built–in objects have only one or two levels of inheritance (e.g. function instances inherit from Function.prototype and Object.prototype). Host objects (e.g. DOM elements) may have longer chains, but that is for convenience and not really necessary (at least one very popular browser didn't implement prototype inheritance for host objects until recently).
You're on the right track. You don't want to mutate Animal's prototype because that breaks the concept of inheritance. As was mentioned in the comments, using Object.create() is the correct way to inherit properties and methods from one object to another. A simple example of prototypical inheritance, using your example, is achieved this way:
function Animal(name) {
this.name = name;
}
Animal.prototype = {
getName: function() {
return this.name;
}
};
function Cat(name, color) {
Animal.call(this, name);
this.color = color;
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
Cat.prototype.getColor = function() {
return this.color;
};
var animal = new Animal('Bob');
var cat = new Cat('Tabby', 'black');
console.log(cat.getName());
console.log(cat.getColor());
console.log(animal.getName());
console.log(animal.getColor()); // throws an error
Hi inheritance in JavaScript is rather complex and you will have to have a good understanding of the prototype object. Ill suggest you use the inheritance pattern of for instance TypeScript. You can give it a try on the Playground
Take a look at this:
var extends = this.extends || function (class, parent) {
for (var property in parent) {
if (parent.hasOwnProperty(property)) {
class[property] = parent[property];
}
}
function newClass() {
this.constructor = class;
}
newClass.prototype = parent.prototype;
class.prototype = new newClass();
};
var Animal = (function () {
function Animal(name) {
this.name = name;
}
return Animal;
})();
var Cat = (function (_super) {
extends(Cat, _super);
function Cat(name) {
_super.call(this, name);
}
Cat.prototype.sayHi = function () {
return "Hello my name is:" + this.name;
};
return Cat;
})(Animal);
You seem to be mixing the prototype property of functions with the internal [[proto]] property of all objects (including functions). They are two distinct things.
Mutating the internal [[proto]] property of an object is discouraged. This can be done either via setPrototypeOf or via the __proto__ accessor, which is inherited from Object.prototype:
var a = {}; // `a` inherits directly from `Object.prototype`
var b = {}; // `b` inherits directly from `Object.prototype`
a.__proto__ = b; // `a` now inherits directly from `b`
// or
Object.setPrototypeOf(a, b); // `a` now inherits directly from `b`
This is what is discouraged, mutating the internal [[proto]] property of an object after it has been created. However, it should be noted that while the object is being created it's alright to assign any object as its internal [[proto]] property.
For example, many JavaScript programmers wish to create functions which inherit from some object other than Function.prototype. This is currently only possible by mutating the internal [[proto]] property of a function after it has been created. However, in ES6 you will be able to assign the internal [[proto]] property of an object when it is created (thus avoiding the problem of mutating the internal [[proto]] property of the object).
For example, consider this bad code:
var callbackFunctionPrototype = {
describe: function () {
alert("This is a callback.");
}
};
var callback = function () {
alert("Hello World!");
};
callback.__proto__ = callbackFunctionPrototype; // mutating [[proto]]
callback.describe();
It can be rewritten in ES6 as follows:
var callbackFunctionPrototype = {
describe: function () {
alert("This is a callback.");
}
};
// assigning [[proto]] at the time of creation, no mutation
var callback = callbackFunctionPrototype <| function () {
alert("Hello World!");
};
callback.describe();
So, mutating the internal [[proto]] property of an object (using either setPrototypeOf or the __proto__ accessor) is bad. However, modifying the prototype property of a function is fine.
The prototype property of a function (let's call the function F) only affects the objects created by new F. For example:
var myPrototype = {
describe: function () {
alert("My own prototype.");
}
};
function F() {}
var a = new F; // inherits from the default `F.prototype`
alert(a.constructor === F); // true - inherited from `F.prototype`
F.prototype = myPrototype; // not mutating the `[[proto]]` of any object
var b = new F; // inherits from the new `F.prototype` (i.e. `myPrototype`)
b.describe();
To know more about inheritance in JavaScript read the answer to the following question:
JavaScript inheritance and the constructor property
Hope that helps.
In Simple words why we use prototype.constructor. I am reading an article about inheritance where I saw prototype.constructor. I see no difference in result when I comment that code. So my question why and when to use it practically.
function Mammal(name){
this.name=name;
this.action= function (){
alert('0')
}
}
function Cat(name){
this.name=name;
}
Cat.prototype = new Mammal();
//Cat.prototype.constructor=Cat; // Otherwise instances of Cat would have a constructor of Mammal
Cat.prototype.action=function(){
alert('1')
}
var y= new Mammal()
var x= new Cat()
y.action()
x.action()
It's mostly convention. Although nothing in JavaScript itself uses the constructor property, sometimes people use it in their code, assuming that it will refer back to the object's constructor. It's not just convention anymore, see ¹ for details.
When you create a function:
function Cat() {
}
The function starts out with an object on its prototype property that has a property called constructor that points back to the function:
console.log(Cat.prototype.constructor === Cat); // true
This is in the specification. (It's also the only place in the specification that property is mentioned — e.g., JavaScript, itself, makes no use of this property at all. Not anymore.¹)
Consequently, instances created with that prototype (whether created via the constructor function or other ways) inherit that constructor property:
var c = new Cat();
console.log(c.constructor === Cat); // true
var c2 = Object.create(Cat.prototype);
console.log(c2.constructor === Cat); // true, even though Cat wasn't used
When you replace the prototype property on a function, as you typically do when building hierarchies:
Cat.prototype = new Mammal(); // This is an anti-pattern, btw, see below
...you end up with an object on Cat.prototype where constructor points to Mammal. Since that's not what one normally expects, it's customary to fix it:
Cat.prototype.constructor = Cat;
Although nothing in JavaScript itself uses the property (it does now¹), sometimes people use it in their code, assuming that it will refer back to the object's constructor.
Re the anti-pattern in that code: When using constructor functions to build a hierarchy, it's not best practice to actually call the "base" constructor to create the "derived" constructor's prototype. Instead, use Object.create to create the prototype:
Cat.prototype = Object.create(Mammal.prototype);
Cat.prototype.constructor = Cat;
...and then chain to Mammal in Cat:
function Cat() {
Mammal.call(this);
// ...
}
Why do it that way? Consider: What if the base requires arguments you won't get until construction-time to meaningfully initialize an instance? You can't pass it arguments until you have them. The pattern above allows you to handle that situation.
Note that Object.create was added in ES5 and so is missing from some old browsers (like IE8). The single-argument version of it can be shimmed/polyfilled trivially, though:
if (!Object.create) {
Object.create = function(proto, props) {
if (typeof props !== "undefined") {
throw new Error("The second argument of Object.create cannot be shimmed.");
}
function f() { }
f.prototype = proto;
return new f;
};
}
I'll just note that constructor functions are just one way of building object hierarchies in JavaScript. They're not the only way, because JavaScript uses prototypical inheritance. JavaScript is so powerful you can use constructor functions to get something similar to class-like inheritance, but it also lets you do more traditional prototypical-style inheritance directly.
¹ "Although nothing in JavaScript itself uses the constructor property..." That's not true anymore as of ES2015 (aka "ES6"). Now, the constructor property is used in a couple of places (such as the SpeciesConstructor and ArraySpeciesCreate abstract operations), which are used in various classes that have methods returning new instances of the class, such as Array#slice and Promise#then. It's used in those places to ensure that subclasses work correctly: E.g., if you subclass Array, and use slice on an instance of the subclass, the array returned by slice is an instance of your subclass, not a raw Array — because slice uses ArraySpeciesCreate.
I am learning the js prototype, and I am wondering if there are any differences between the following two segment?
Segment1:
function SuperType(){
this.color=["blue","yellow"];
}
function SubType(){
}
Subtype.prototype = new SuperType();
Segment2:
function SuperType(){
this.color=["blue","yellow"];
}
function SubType(){
SuperType.call(this);
}
and if the above two does the same thing, then why some codes bother to do this:
function SubType(){
SuperType.call(this);
}
SubType.prototype=new SuperType();
Yes, there are differences.
In Segment 1, the subclass SubType does not call the constructor of SuperType so it never gets executed. Segment 1 is not a correct general purpose way to inherit from another object.
In Segment 2, the subclass SubType does call the constructor of SuperType so the statement this.color=["blue","yellow"]; gets executed, but the prototype is not set appropriately so any prototype items that SuperType might have had are not inherited. Segment 2 is not a correct general purpose way to inherit from another object.
Segment 1 would work properly if there was no code in the SuperType constructor (not the case in your example). As you show it, because the SuperType() constructor is not called, this.color would only be in the prototype and thus the same array would be shared by all instances which is generally NOT what you want. Calling the constructor properly would give every instance it's own copy of this.color, not a shared copy.
Segment 2 would work properly if nothing was added to the SuperType prototype and there are no constructor arguments for SuperType (happens to be the case in your example, but not a good general practice).
Neither is a good general purpose way of doing things.
Your last option is the proper general purpose way to do things because it both inherits from the prototype AND it executes the constructor of the inherited object.
The most general purpose way also passes any constructor arguments to the inherited object using .apply(this, arguments) like this and initializes its own prototype and sets it's constructor property.
// define base object constructor
function SuperType(){
this.color=["blue","yellow"];
}
// define base object methods on the prototype
SuperType.prototype.foo = function() {};
// ---------------------------------------------------------------------------
// define object that wants to inherit from the SuperType object
function SubType() {
// call base object constructor with all arguments that might have been passed
SuperType.apply(this, arguments);
}
// set prototype for this object to point to base object
// so we inherit any items set on the base object's prototype
SubType.prototype = new SuperType();
// reset constructor to point to this object not to SuperType
SubType.prototype.constructor = SubType;
// define any methods of this object by adding them to the prototype
SubType.prototype.myMethod = function() {};
If you are willing to only support IE9 and above, then you should change this line:
SubType.prototype = new SuperType();
to this:
SubType.prototype = Object.create(SuperType.prototype);
This avoids calling the SuperType() constructor in order to just get an object to use for the prototype. In most cases this really doesn't matter, but in cases where the constructor has side effects outside of just initializing it's own properties, it can matter.
In segment 1 the prototype gets set correctly but the constructor function of SuperType never gets called.
At the start of segment 2 the constructor function of the SuperType gets called but the prototype is not set.
The last example is correct because it sets up the prototype correctly as well as calls the SuperType's constructor function.
function SuperType() {
// Do some stuff.
}
function SubType() {
SuperType.apply(this, arguments);
}
SubType.prototype = new SuperType();
you should not set prototype inheritance with
SubType.prototype=new SuperType ();
because there can be problems.
if you do that like this, the prototype of SubType would also inherit the property color as own property of the SubType prototype, because the constructor is worked through. Every new instance of subType has then a reference to the color property in the prototype and is not an own property of the instance itself, this is finally not what you want because you only want to inherit the prototype. the luck is that after calling the super constructer every instance gets an own color property , but the color property is still also defined in the prototype. there is no need
so to really inherit only the prototype you should use Object.create or do a workaround like this.
function SuperType()
{
if (SuperType.doNotConstruct) return;
this.color=["blue","yellow"];
}
function SubType()
{
SuperType.call (this);
}
SuperType.doNotConstruct=true;
SubType.prototype = new SuperType();
SuperType.doNotConstruct=false;
SubType.prototype.constructor=SubType;
second way - better way - because no if Statement in the constructor is needed
function SuperType()
{
this.color=["blue","yellow"];
}
function SubType()
{
SuperType.call (this);
}
var CLASS=function () {}
CLASS.prototype=SuperType.prototype;
SubType.prototype=new CLASS ();
SubType.prototype.constructor=SubType;
#blake try the following - this will show a problem when people forget to call the super constructor and do inheritation with ...prototype=new constructor
function SuperType()
{
this.color=["blue","yellow"];
}
SuperType.prototype.addColor=function (name)
{
this.color.push ("red");
}
function SubType () {}
SubType.prototype=new SuperType ();
var a=new SubType ();
var b=new SubType ();
a.addColor ("red");
console.log (a.color);
console.log (b.color);
In JavaScript what is the difference between these two examples:
Prerequisite:
function SomeBaseClass(){
}
SomeBaseClass.prototype = {
doThis : function(){
},
doThat : function(){
}
}
Inheritance example A using Object.create:
function MyClass(){
}
MyClass.prototype = Object.create(SomeBaseClass.prototype);
Inheritance example B using the new keyword
function MyClass(){
}
MyClass.prototype = new SomeBaseClass();
Both examples seem to do the same thing. When would you chose one over the other?
An additional question:
Consider code in below link (line 15), where a reference to the the function's own constructor is stored in the prototype. Why is this useful?
https://github.com/mrdoob/three.js/blob/master/src/loaders/ImageLoader.js
Excerpt (if you don't want to open the link):
THREE.ImageLoader.prototype = {
constructor: THREE.ImageLoader
}
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.
Both examples seem to do the same thing.
That's true in your case.
When would you chose one over the other?
When SomeBaseClass has a function body, this would get executed with the new keyword. This usually is not intended - you only want to set up the prototype chain. In some cases it even could cause serious issues because you actually instantiate an object, whose private-scoped variables are shared by all MyClass instances as they inherit the same privileged methods. Other side effects are imaginable.
So, you should generally prefer Object.create. Yet, it is not supported in some legacy browsers; which is the reason you see the new-approach much too frequent as it often does no (obvious) harm. Also have a look at this answer.
The difference becomes obvious if you use Object.create() as it is intended. Actually, it does entirely hideout the prototype word from your code, it'll do the job under the hood. Using Object.create(), we can go like
var base = {
doThis : function(){
},
doThat : function(){
}
};
And then we can extend/inherit other objects from this
var myObject = Object.create( base );
// myObject will now link to "base" via the prototype chain internally
So this is another concept, a more "object oriented" way of inherting. There is no "constructor function" out of the box using Object.create() for instance. But of course you could just create and call a self defined constructor function within those objects.
One argument for using Object.create() is that it might look more natural to mix/*inherit* from other objects, than using Javascripts default way.
I am not an expert in java script but here is a simple example to understand difference between "Object.create" and "new" ..
step 1 : create the parent function with some properties and actions..
function Person() {
this.name = 'venkat';
this.address = 'dallas';
this.mobile='xxxxxxxxxx'
}
Person.prototype.func1 = function () {
return this.name + this.address;
}
step 2 : create a child function (PersonSalary) which extends above Person function using New keyword..
function PersonSalary() {
Person.call(this);
}
PersonSalary.prototype = new Person();
PersonSalary();
step 3 : create second child function (PersonLeaves) which extends above Person function using Object.create keyword..
function PersonLeaves() {
Person.call(this);
}
PersonLeaves.prototype = Object.create(Person.prototype);
PersonLeaves();
// Now check both child functions prototypes.
PersonSalary.prototype
PersonLeaves.prototype
both of these child functions will link to Person(parent function) prototype and can access it's methods but if you create child function using new it will return a brand new object with all parent properties which we don't need and also when you create any object or function using "New" that parent function is executed which we don't want to be.
Here are the takeaways
if you just want to delegate to some methods in parent function and don't want a new object to be created , using Object.create is best way.
A couple of additions to this answer set, mindful that JS obviously now has native classes:
In both Example A and Example B the static inheritance chain is not configured.
In Example B the superclass constructor is run at the "wrong time". It is run before the call to instantiate an instance of the subclass, before any arguments are known and perhaps before you have decided to instantiate an instance of the subclass. Note that constructors can contain any logic they like, including side-effectful logic, so this can be impactful.
Post-ES6 the inheritance chain can be configured in a standardised way using the class and extends keywords (which solve both of these issues).
See also.
i don't get why everyone is using Boy.prototype = new Human; to simulate inheritance. Look, what we want is the function's of A right? we can do that without instantiating a new A (in fact instantiating a new A does give us undesirable results, in the sense that we are actually running the instantiating function which isn't what we want)
So isn't this a better solution?
for (var prop_name in Human.prototype) {
Object.defineProperty(
Boy.prototype,
prop_name,
Object.getOwnPropertyDescriptor(Human.prototype,prop_name)
);
}
Say we are that particular and want not only the enumerable properties in Human.prototype we could still achieve it by using Object.getOwnPropertyNames and calling it on the prototype chain, which in turn is available to us through Object.getPrototypeOf.
So what exactly is the benefit of doing Boy.prototype = new Human; to simulate inheritance when we have better options available to us?
A better option is to create an intermediate to hold the prototype.
function extend(clazz, superclass) {
var intermediate = function() {};
intermediate.prototype = superclass.prototype;
clazz.prototype = new intermediate();
// Following line is optional, but useful
clazz.prototype.constructor = clazz;
}
This avoids unnecessary copying, but still means that you don't need to instantiate an object that will do work in its constructor. It also sets up the prototype chain so that you can use instanceof. It also doesn't result in superclass prototype contamination which some inheritance antipatterns can.
For completeness, your subclass should call the superclass constructor in its constructor, which you can do with Superclass.call(this);.
EDIT: Since ES5, you can replace calls to extend with
Subclass.prototype = Object.create(Superclass.prototype);
which does the same thing.
It sets up the prototype chain correctly, meaning that instanceof and isPrototypeOf() will work
It's less verbose
There are simple but ugly workarounds to prevent a constructor function from performing its usual initialization when you're just using it to create a prototype object. For example, you could either check the arguments:
function Boy(name) {
if (arguments.length == 1) {
this.name = name;
// Do other initialization
}
}
... or move the initialization into a separate method that has to be called explicitly:
function Boy(name) {}
Boy.prototype.init = function(name) {
this.name = name;
// Do other initialization
}
This has the obvious downside of requiring you to remember to call init() whenever you create a new Boy.
In ECMAScript 5 environments (current versions of most browsers, for example), a better option may be ECMAScript 5's Object.create(), which allows you to create an object which inherits directly from another object and sets up the prototype chain for you. This can be emulated (but only approximately: see Object.defineProperty in ES5?) in non-ES5 environments:
if (!Object.create) {
Object.create = function(o) {
function F() {}
F.prototype = o;
return new F();
};
}