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);
Related
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/
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've been using code like this for inheriting from another object:
// define base object constructor
function SuperType(){
// constructor code
}
// 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);
// other constructor code
}
// 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() {};
My question is why do you have to set the SubType.constructor = SubType? When is the .constructor property actually used? If you create a SubType object like this:
var s = new SubType();
That's going to call the SubType() constructor regardless of what SubType.prototype.constructor is actually set to, so I'm trying to understand when the .constructor property is ever actually used?
As you can see in this jsFiddle demo with the assignment to .constructor commented out, the proper constructor is still called. So, it appears that the .constructor property is not used in normal construction with the new operator. I'm wondering when it is used?
According to the The ECMAScript Language Specification,
The initial value of Object.prototype.constructor is the standard built-in Object constructor.
In other words, it's just a pointer to the Object's actual, native constructor-- The one that is called via new Object(). Thus, you can override it without changing anything about how new Object() works.
So why does it exist? Because constructor functions are effectively classes in JavaScript, it lets you do certain things with class instances without needing to their class name. To borrow from Axel Rauschmayer's blog, the constructor property allows:
Comparing between classes, i.e. a.constructor === b.constructor
Creating a new instance from an existing instance, i.e. new a.constructor()
Invoking another (super)class's constructor
All without any hardcoded references to class names. Again, it's not really meant to be overridden. To echo the above comments, I've never really seen someone override it in the wild.
If I have the following:
function Constructor1(data){
...
...
...};
function Constructor2(data){
Constructor1.prototype.constructor.call(this, data);
...
...
...
}
Constructor2.prototype = new Constructor1();
Then how can I later determine the difference between how they were constructed? I know I can do if (testObject instanceof Constructor2) but if I have a LOT of inherited objects I don't want to do that test for everything. Is there any way to get the string 'Constructor2' returned somehow? (Or whatever the first constructor function called) is?
You can call the parent like this: Parent.call(this,args).
You should not create an instance of Parent to set the prototype part of the inheritance in Child.
If you set the prototype without destroying the prototype.constructor in Child you can use the name property of the constructor function:
function Parent(args){
};
function Child(args){
Parent.call(this,args);
};
console.log(Child.prototype.constructor.name);//=Child
//overwrithing Child.prototype so also Child.prototype.constructor
Child.prototype=Object.create(Parent.prototype);
console.log(Child.prototype.constructor.name);//=Parent, needs to be fixed
Child.prototype.constructor=Child;//fixed
var c = new Child();
console.log(c.constructor.name);//=Child
The name property of Function isn't standard so no guarantee about it's behavior:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
You may want to check using the function itself: (this.constructor===Parent)
More on constructor functions and prototype here.
I am learning javascript and got puzzled. An example over here which has example as below:-
// define the Person Class
function Person() {}
Person.prototype.walk = function(){
alert ('I am walking!');
};
Person.prototype.sayHello = function(){
alert ('hello');
};
// define the Student class
function Student() {
// Call the parent constructor
Person.call(this);// <---- Confusion
}
// inherit Person
Student.prototype = new Person(); //<---- Confusion
// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;
// replace the sayHello method
Student.prototype.sayHello = function(){
alert('hi, I am a student');
}
// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
alert('goodBye');
}
var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();
// check inheritance
alert(student1 instanceof Person); // true
alert(student1 instanceof Student); // true
Now, I am confused (<----) in these two lines. When I say Person.call(this);, this is simply stating to Inherit properties of Person class... Right?
Then what is this doing?
// inherit Person
Student.prototype = new Person(); //<---- Confusion
As per my knowledge, .prototype also inherits all properties?
To explain it, first let's remember how constructor functions work in JavaScript:
function Guide(a) {
this.a = a;
}
Guide.prototype.q = "Life, the Universe, and Everything";
var g = new Guide(42);
console.log(g.q); // "Life, the Universe, and Everything"
console.log(g.a); // 42
When we do new Guide(42), the new operator creates a new object and assigns it a prototype using the Guide.prototype property. Then new calls Guide, passing in that new object as this. Guide uses this to add properties to the new object that aren't on its prototype. Then the new expression completes and its result is the new object that it created.
When we look at g.q, since the g object doesn't have its own property called q, the JavaScript engine looks at g's prototype, which (again) it got assigned when it was created. That prototype has a q property, and so the engine uses its value.
In contrast, when we look at g.a, the g object has its own property called a, and so the value is used directly.
With that foundation in place, let's look at Student and Parent:
function Student() {
// Call the parent constructor
Person.call(this);// <---- Confusion
}
When we call new Student(), within the call to Student, this is (again) the new object created by the new operator, which has Student.prototype as its underlying prototype. But the Parent function hasn't had a chance to do anything with this new object. So what that line does is give Parent a chance to do whatever it needs to do to new objects that it can't do via the prototype, like our Guide function earlier assigning to this.a. In technical terms, Parent.call(this); calls the Parent function, ensuring that this within the call to Parent is the value passed into call (which is, in this case, the this of the call to Student — e.g., the new object). If you're familiar with class-based languages, this is like doing super(); (that's Java, but you get the idea) in a derived constructor: It gives the base constructor a chance to initialize the object.
// inherit Person
Student.prototype = new Person(); //<---- Confusion
Since Student is supposed to inherit from Person, what that code is doing is creating the prototype that will be assigned to objects created via new Student. The object it's creating is a Person object.
FWIW, that code isn't quite implementing the construction chain correctly (it's calling Person more often than it should [both when creating Student.prototype and when Student is called], and failing to set constructor).
The more correct way to create Student's prototype property, if we're going to call Parent from within Student, looks like this:
function derive(child, parent) {
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor();
}
derive(Student, Parent);
That way, we get a prototype based on Parent.prototype but without calling Parent. It's an either-or: Either call Parent to create Student.prototype, or call Parent within Student, but don't do both. When building hierarchies with constructor functions, typically you want to call the parent from the child constructor, rather than when creating the child prototype. When using direct object inheritance (without constructor functions), of course you do it the other way.
If you're interested in inheritance in JavaScript, I've written a helper script called Lineage you might want to look at, and in particular even if you don't use Lineage, this discussion on its wiki page may be useful for understanding inheritance hierarchies.