Why constructor of A object is executed even though we change it manually to another constructor while...
function Animal() { console.log("Animal")}
function Bird() { console.log("Bird")}
function Dog() { console.log("Dog")}
Bird.prototype = Object.create(Animal.prototype);
Dog.prototype = Object.create(Animal.prototype);
duck = new Bird();
beagle = new Dog();
In the above code - we inherit Bird and Dog from Animal.
Their prototype will be animal. So by Default Bird.constructor will be pointing to Animal constructor.
When new Bird() is executed. I expect "Animal to be logged on console" but Bird is logged. Since the constructor is Animal. Animal constructor should be executed right? Correct my understanding
javascript object
add a comment |
function Animal() { console.log("Animal")}
function Bird() { console.log("Bird")}
function Dog() { console.log("Dog")}
Bird.prototype = Object.create(Animal.prototype);
Dog.prototype = Object.create(Animal.prototype);
duck = new Bird();
beagle = new Dog();
In the above code - we inherit Bird and Dog from Animal.
Their prototype will be animal. So by Default Bird.constructor will be pointing to Animal constructor.
When new Bird() is executed. I expect "Animal to be logged on console" but Bird is logged. Since the constructor is Animal. Animal constructor should be executed right? Correct my understanding
javascript object
1
your assertions are not correct.
– Pointy
Nov 25 '18 at 17:30
Can you tell me the reasons @Pointy
– Tharun26
Nov 25 '18 at 17:31
yes working on it :)
– Pointy
Nov 25 '18 at 17:32
prototype and constructor are different things.
– trincot
Nov 25 '18 at 17:34
1
"Whennew Bird()
is executed I expect "Animal" to be logged on console" - Why?Bird
is defined asfunction Bird() { console.log("Bird") }
so that's what you get when calling it.
– Bergi
Nov 25 '18 at 17:39
add a comment |
function Animal() { console.log("Animal")}
function Bird() { console.log("Bird")}
function Dog() { console.log("Dog")}
Bird.prototype = Object.create(Animal.prototype);
Dog.prototype = Object.create(Animal.prototype);
duck = new Bird();
beagle = new Dog();
In the above code - we inherit Bird and Dog from Animal.
Their prototype will be animal. So by Default Bird.constructor will be pointing to Animal constructor.
When new Bird() is executed. I expect "Animal to be logged on console" but Bird is logged. Since the constructor is Animal. Animal constructor should be executed right? Correct my understanding
javascript object
function Animal() { console.log("Animal")}
function Bird() { console.log("Bird")}
function Dog() { console.log("Dog")}
Bird.prototype = Object.create(Animal.prototype);
Dog.prototype = Object.create(Animal.prototype);
duck = new Bird();
beagle = new Dog();
In the above code - we inherit Bird and Dog from Animal.
Their prototype will be animal. So by Default Bird.constructor will be pointing to Animal constructor.
When new Bird() is executed. I expect "Animal to be logged on console" but Bird is logged. Since the constructor is Animal. Animal constructor should be executed right? Correct my understanding
javascript object
javascript object
asked Nov 25 '18 at 17:28
Tharun26Tharun26
150110
150110
1
your assertions are not correct.
– Pointy
Nov 25 '18 at 17:30
Can you tell me the reasons @Pointy
– Tharun26
Nov 25 '18 at 17:31
yes working on it :)
– Pointy
Nov 25 '18 at 17:32
prototype and constructor are different things.
– trincot
Nov 25 '18 at 17:34
1
"Whennew Bird()
is executed I expect "Animal" to be logged on console" - Why?Bird
is defined asfunction Bird() { console.log("Bird") }
so that's what you get when calling it.
– Bergi
Nov 25 '18 at 17:39
add a comment |
1
your assertions are not correct.
– Pointy
Nov 25 '18 at 17:30
Can you tell me the reasons @Pointy
– Tharun26
Nov 25 '18 at 17:31
yes working on it :)
– Pointy
Nov 25 '18 at 17:32
prototype and constructor are different things.
– trincot
Nov 25 '18 at 17:34
1
"Whennew Bird()
is executed I expect "Animal" to be logged on console" - Why?Bird
is defined asfunction Bird() { console.log("Bird") }
so that's what you get when calling it.
– Bergi
Nov 25 '18 at 17:39
1
1
your assertions are not correct.
– Pointy
Nov 25 '18 at 17:30
your assertions are not correct.
– Pointy
Nov 25 '18 at 17:30
Can you tell me the reasons @Pointy
– Tharun26
Nov 25 '18 at 17:31
Can you tell me the reasons @Pointy
– Tharun26
Nov 25 '18 at 17:31
yes working on it :)
– Pointy
Nov 25 '18 at 17:32
yes working on it :)
– Pointy
Nov 25 '18 at 17:32
prototype and constructor are different things.
– trincot
Nov 25 '18 at 17:34
prototype and constructor are different things.
– trincot
Nov 25 '18 at 17:34
1
1
"When
new Bird()
is executed I expect "Animal" to be logged on console" - Why? Bird
is defined as function Bird() { console.log("Bird") }
so that's what you get when calling it.– Bergi
Nov 25 '18 at 17:39
"When
new Bird()
is executed I expect "Animal" to be logged on console" - Why? Bird
is defined as function Bird() { console.log("Bird") }
so that's what you get when calling it.– Bergi
Nov 25 '18 at 17:39
add a comment |
2 Answers
2
active
oldest
votes
You are confusing inheritance with constructor calls. When you say:
duck = new Bird();
you are making an explicit call to the Bird
constructor function so, of course, Bird
will fire.
While Object.create()
is a handy way of causing one object to inherit from another, you still have to manually set up the constructor chain. A good way to understand this is when both constructors take arguments (shown below).
See comments inline:
function Animal(gender) {
// The argument allows the instance property to initialize.
// gender will be a property of Animal and will be inherited
// by anything that inherits from Animal later. But, that
// doesn't change the fact that the Animal constructor
// must be called and passed the gender for the Animal
// to be properly initialized.
this.gender = gender;
// Get the caller of this function (non-standard technique - just used for demo).
// If the caller is null, it means that Animal was called directly. If not,
// we can get the name of the calling function:
var caller = Animal.caller ? Animal.caller.name : "Animal";
// Report of newly constructed Animal
console.log("Animal is a " + this.gender + ". (called by: " + caller + ")");
}
function Bird(gender, canFly) {
// Because a bird inherits from an Animal, you have
// to manually ensure that when a new Bird is created
// the Animal constructor gets called. You can see
// why this is necessary as we have a situation where
// the prototype's constructor is expecting an argument
// that we've received when the constructor of the
// derived object was called. We certainly don't want
// to have to rewrite the code that sets the gender, so
// we call the prototype's constructor and pass it what
// it is expecting and allow it to do some of the object
// initialization for us:
Animal.prototype.constructor.call(this, gender);
// Arguments meant for the current constructor are handled
// in the current constructor
this.canFly = canFly
// The inherited properties are available:
console.log("Bird is a " + this.gender + " and it can fly: " + this.canFly);
}
// This just causes Bird to inherit from Animal. This alone
// doesn't cause the Animal constructor to fire when new Bird()
// is executed.
Bird.prototype = Object.create(Animal.prototype);
// By using a different prototype, we have wiped out the native
// constructor so we will reset just the contstructor so that
// constructions of Bird work properly
Bird.prototype.constructor = Bird;
// Just a test to show that making an Animal properly
// requires that the Animal constructor be called and
// passed a gender.
console.log("--- Creating New Animal ---");
var generic = new Animal("male");
// You are explicitly invoking the Bird constructor here.
// It's going to fire that function. That function, in turn,
// is configured to invoke the prototype object's constructor.
// The gender property will be handled by the Animal constructor
// and the canFly will be handled by the Bird constructor.
console.log("--- Creating New Bird ---");
duck = new Bird("female", false);
// ************************************************
function Falcon(gender, canFly, trained){
// We'll pass the arguments needed by the parent object to it
Bird.prototype.constructor.call(this, gender, canFly);
// And set current instance properties right here
this.trained = trained;
console.log("Bird is a " + this.gender + ", can fly: " + this.canFly + " and is trained: " + this.trained);
}
Falcon.prototype = Object.create(Bird.prototype);
// By using a different prototype, we have wiped out the native
// constructor so we will reset just the contstructor so that
// constructions of Falcon work properly
Falcon.prototype.constructor = Falcon;
console.log("--- Creating New Falcon ---");
let f = new Falcon("female", true, false);
When you set theBird
prototype toBird.prototype = Object.create(Animal.prototype);
what happens toBird.prototype.constructor
? If I want to make a class that inherits fromBird
how do I call it's constructor?
– Mark Meyer
Nov 25 '18 at 18:07
@MarkMeyer When you setBird.prototype = Object.create(Animal.prototype)
, it doesn't mean that when you invokeBird()
thatAnimal()
will fire. It simply means thatBird.prototype
now equalsAnimal.prototype
. And,Bird.prototype.constructor
now equalsAnimal
. But, that's where you are getting confused.Bird.prototype.constructor == Animal
(becauseBird.prototype
isAnimal
), notBird.constructor
. That is stillBird
.
– Scott Marcus
Nov 25 '18 at 18:11
I think you misunderstood me. When you subclass animal you do:Animal.prototype.constructor.call(this, gender)
to set the super's instance variables likegender
. Now lets say I want to make aFalcon
class that inherits fromBird
so in it's constructor I callBird.prototype.constructor.call(this, gender, true)
Does it setcanFly
to true on my Falcon instance? Easy to show in code: repl.it/@ak_mark/GroundedLastEvents The issue is theBird.prototype.constructor
no longer points toBird()
.
– Mark Meyer
Nov 25 '18 at 18:22
All I'm saying is that if I try to subclassBird
the same wayBird
subclassesAnimal
it doesn't work. I'm doing exactly the same thing with Falcon in the repl.it; repl.it/@ak_mark/GroundedLastEvents What am I missing in the repl?
– Mark Meyer
Nov 25 '18 at 18:44
@MarkMeyer I see what you are saying. Yes, swapping theprototype
does become an issue here and the solution is to manually correct theprototype.constructor
after setting the prototype. This works becauseObject.create()
make a new, distinct instance of the prototype object for the sub-object. Changing its constructor won't change it for the entire group - only for derived types. I've updated my answer to show this.
– Scott Marcus
Nov 25 '18 at 18:55
|
show 3 more comments
The statement
Bird.prototype = Object.create(Animal.prototype);
makes the prototype object of the Bird
constructor be a new object whose own prototype is the Animal
prototype, not the Animal
constructor itself.
Thus
duck = new Bird()
makes a new object whose constructor is Bird
, whose prototype is the Bird
prototype, which in turn inherits from the Animal
prototype.
This way, your Animal
prototype could have a method called eat()
, so a call to
duck.eat("fish")
would effectively be a call to the eat()
method on the Animal
prototype. Why? Well there's no "eat" property directly on the duck
object, and none on the Bird
prototype, but there is an "eat" property on the Animal
prototype.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53470033%2fwhy-constructor-of-a-object-is-executed-even-though-we-change-it-manually-to-ano%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
You are confusing inheritance with constructor calls. When you say:
duck = new Bird();
you are making an explicit call to the Bird
constructor function so, of course, Bird
will fire.
While Object.create()
is a handy way of causing one object to inherit from another, you still have to manually set up the constructor chain. A good way to understand this is when both constructors take arguments (shown below).
See comments inline:
function Animal(gender) {
// The argument allows the instance property to initialize.
// gender will be a property of Animal and will be inherited
// by anything that inherits from Animal later. But, that
// doesn't change the fact that the Animal constructor
// must be called and passed the gender for the Animal
// to be properly initialized.
this.gender = gender;
// Get the caller of this function (non-standard technique - just used for demo).
// If the caller is null, it means that Animal was called directly. If not,
// we can get the name of the calling function:
var caller = Animal.caller ? Animal.caller.name : "Animal";
// Report of newly constructed Animal
console.log("Animal is a " + this.gender + ". (called by: " + caller + ")");
}
function Bird(gender, canFly) {
// Because a bird inherits from an Animal, you have
// to manually ensure that when a new Bird is created
// the Animal constructor gets called. You can see
// why this is necessary as we have a situation where
// the prototype's constructor is expecting an argument
// that we've received when the constructor of the
// derived object was called. We certainly don't want
// to have to rewrite the code that sets the gender, so
// we call the prototype's constructor and pass it what
// it is expecting and allow it to do some of the object
// initialization for us:
Animal.prototype.constructor.call(this, gender);
// Arguments meant for the current constructor are handled
// in the current constructor
this.canFly = canFly
// The inherited properties are available:
console.log("Bird is a " + this.gender + " and it can fly: " + this.canFly);
}
// This just causes Bird to inherit from Animal. This alone
// doesn't cause the Animal constructor to fire when new Bird()
// is executed.
Bird.prototype = Object.create(Animal.prototype);
// By using a different prototype, we have wiped out the native
// constructor so we will reset just the contstructor so that
// constructions of Bird work properly
Bird.prototype.constructor = Bird;
// Just a test to show that making an Animal properly
// requires that the Animal constructor be called and
// passed a gender.
console.log("--- Creating New Animal ---");
var generic = new Animal("male");
// You are explicitly invoking the Bird constructor here.
// It's going to fire that function. That function, in turn,
// is configured to invoke the prototype object's constructor.
// The gender property will be handled by the Animal constructor
// and the canFly will be handled by the Bird constructor.
console.log("--- Creating New Bird ---");
duck = new Bird("female", false);
// ************************************************
function Falcon(gender, canFly, trained){
// We'll pass the arguments needed by the parent object to it
Bird.prototype.constructor.call(this, gender, canFly);
// And set current instance properties right here
this.trained = trained;
console.log("Bird is a " + this.gender + ", can fly: " + this.canFly + " and is trained: " + this.trained);
}
Falcon.prototype = Object.create(Bird.prototype);
// By using a different prototype, we have wiped out the native
// constructor so we will reset just the contstructor so that
// constructions of Falcon work properly
Falcon.prototype.constructor = Falcon;
console.log("--- Creating New Falcon ---");
let f = new Falcon("female", true, false);
When you set theBird
prototype toBird.prototype = Object.create(Animal.prototype);
what happens toBird.prototype.constructor
? If I want to make a class that inherits fromBird
how do I call it's constructor?
– Mark Meyer
Nov 25 '18 at 18:07
@MarkMeyer When you setBird.prototype = Object.create(Animal.prototype)
, it doesn't mean that when you invokeBird()
thatAnimal()
will fire. It simply means thatBird.prototype
now equalsAnimal.prototype
. And,Bird.prototype.constructor
now equalsAnimal
. But, that's where you are getting confused.Bird.prototype.constructor == Animal
(becauseBird.prototype
isAnimal
), notBird.constructor
. That is stillBird
.
– Scott Marcus
Nov 25 '18 at 18:11
I think you misunderstood me. When you subclass animal you do:Animal.prototype.constructor.call(this, gender)
to set the super's instance variables likegender
. Now lets say I want to make aFalcon
class that inherits fromBird
so in it's constructor I callBird.prototype.constructor.call(this, gender, true)
Does it setcanFly
to true on my Falcon instance? Easy to show in code: repl.it/@ak_mark/GroundedLastEvents The issue is theBird.prototype.constructor
no longer points toBird()
.
– Mark Meyer
Nov 25 '18 at 18:22
All I'm saying is that if I try to subclassBird
the same wayBird
subclassesAnimal
it doesn't work. I'm doing exactly the same thing with Falcon in the repl.it; repl.it/@ak_mark/GroundedLastEvents What am I missing in the repl?
– Mark Meyer
Nov 25 '18 at 18:44
@MarkMeyer I see what you are saying. Yes, swapping theprototype
does become an issue here and the solution is to manually correct theprototype.constructor
after setting the prototype. This works becauseObject.create()
make a new, distinct instance of the prototype object for the sub-object. Changing its constructor won't change it for the entire group - only for derived types. I've updated my answer to show this.
– Scott Marcus
Nov 25 '18 at 18:55
|
show 3 more comments
You are confusing inheritance with constructor calls. When you say:
duck = new Bird();
you are making an explicit call to the Bird
constructor function so, of course, Bird
will fire.
While Object.create()
is a handy way of causing one object to inherit from another, you still have to manually set up the constructor chain. A good way to understand this is when both constructors take arguments (shown below).
See comments inline:
function Animal(gender) {
// The argument allows the instance property to initialize.
// gender will be a property of Animal and will be inherited
// by anything that inherits from Animal later. But, that
// doesn't change the fact that the Animal constructor
// must be called and passed the gender for the Animal
// to be properly initialized.
this.gender = gender;
// Get the caller of this function (non-standard technique - just used for demo).
// If the caller is null, it means that Animal was called directly. If not,
// we can get the name of the calling function:
var caller = Animal.caller ? Animal.caller.name : "Animal";
// Report of newly constructed Animal
console.log("Animal is a " + this.gender + ". (called by: " + caller + ")");
}
function Bird(gender, canFly) {
// Because a bird inherits from an Animal, you have
// to manually ensure that when a new Bird is created
// the Animal constructor gets called. You can see
// why this is necessary as we have a situation where
// the prototype's constructor is expecting an argument
// that we've received when the constructor of the
// derived object was called. We certainly don't want
// to have to rewrite the code that sets the gender, so
// we call the prototype's constructor and pass it what
// it is expecting and allow it to do some of the object
// initialization for us:
Animal.prototype.constructor.call(this, gender);
// Arguments meant for the current constructor are handled
// in the current constructor
this.canFly = canFly
// The inherited properties are available:
console.log("Bird is a " + this.gender + " and it can fly: " + this.canFly);
}
// This just causes Bird to inherit from Animal. This alone
// doesn't cause the Animal constructor to fire when new Bird()
// is executed.
Bird.prototype = Object.create(Animal.prototype);
// By using a different prototype, we have wiped out the native
// constructor so we will reset just the contstructor so that
// constructions of Bird work properly
Bird.prototype.constructor = Bird;
// Just a test to show that making an Animal properly
// requires that the Animal constructor be called and
// passed a gender.
console.log("--- Creating New Animal ---");
var generic = new Animal("male");
// You are explicitly invoking the Bird constructor here.
// It's going to fire that function. That function, in turn,
// is configured to invoke the prototype object's constructor.
// The gender property will be handled by the Animal constructor
// and the canFly will be handled by the Bird constructor.
console.log("--- Creating New Bird ---");
duck = new Bird("female", false);
// ************************************************
function Falcon(gender, canFly, trained){
// We'll pass the arguments needed by the parent object to it
Bird.prototype.constructor.call(this, gender, canFly);
// And set current instance properties right here
this.trained = trained;
console.log("Bird is a " + this.gender + ", can fly: " + this.canFly + " and is trained: " + this.trained);
}
Falcon.prototype = Object.create(Bird.prototype);
// By using a different prototype, we have wiped out the native
// constructor so we will reset just the contstructor so that
// constructions of Falcon work properly
Falcon.prototype.constructor = Falcon;
console.log("--- Creating New Falcon ---");
let f = new Falcon("female", true, false);
When you set theBird
prototype toBird.prototype = Object.create(Animal.prototype);
what happens toBird.prototype.constructor
? If I want to make a class that inherits fromBird
how do I call it's constructor?
– Mark Meyer
Nov 25 '18 at 18:07
@MarkMeyer When you setBird.prototype = Object.create(Animal.prototype)
, it doesn't mean that when you invokeBird()
thatAnimal()
will fire. It simply means thatBird.prototype
now equalsAnimal.prototype
. And,Bird.prototype.constructor
now equalsAnimal
. But, that's where you are getting confused.Bird.prototype.constructor == Animal
(becauseBird.prototype
isAnimal
), notBird.constructor
. That is stillBird
.
– Scott Marcus
Nov 25 '18 at 18:11
I think you misunderstood me. When you subclass animal you do:Animal.prototype.constructor.call(this, gender)
to set the super's instance variables likegender
. Now lets say I want to make aFalcon
class that inherits fromBird
so in it's constructor I callBird.prototype.constructor.call(this, gender, true)
Does it setcanFly
to true on my Falcon instance? Easy to show in code: repl.it/@ak_mark/GroundedLastEvents The issue is theBird.prototype.constructor
no longer points toBird()
.
– Mark Meyer
Nov 25 '18 at 18:22
All I'm saying is that if I try to subclassBird
the same wayBird
subclassesAnimal
it doesn't work. I'm doing exactly the same thing with Falcon in the repl.it; repl.it/@ak_mark/GroundedLastEvents What am I missing in the repl?
– Mark Meyer
Nov 25 '18 at 18:44
@MarkMeyer I see what you are saying. Yes, swapping theprototype
does become an issue here and the solution is to manually correct theprototype.constructor
after setting the prototype. This works becauseObject.create()
make a new, distinct instance of the prototype object for the sub-object. Changing its constructor won't change it for the entire group - only for derived types. I've updated my answer to show this.
– Scott Marcus
Nov 25 '18 at 18:55
|
show 3 more comments
You are confusing inheritance with constructor calls. When you say:
duck = new Bird();
you are making an explicit call to the Bird
constructor function so, of course, Bird
will fire.
While Object.create()
is a handy way of causing one object to inherit from another, you still have to manually set up the constructor chain. A good way to understand this is when both constructors take arguments (shown below).
See comments inline:
function Animal(gender) {
// The argument allows the instance property to initialize.
// gender will be a property of Animal and will be inherited
// by anything that inherits from Animal later. But, that
// doesn't change the fact that the Animal constructor
// must be called and passed the gender for the Animal
// to be properly initialized.
this.gender = gender;
// Get the caller of this function (non-standard technique - just used for demo).
// If the caller is null, it means that Animal was called directly. If not,
// we can get the name of the calling function:
var caller = Animal.caller ? Animal.caller.name : "Animal";
// Report of newly constructed Animal
console.log("Animal is a " + this.gender + ". (called by: " + caller + ")");
}
function Bird(gender, canFly) {
// Because a bird inherits from an Animal, you have
// to manually ensure that when a new Bird is created
// the Animal constructor gets called. You can see
// why this is necessary as we have a situation where
// the prototype's constructor is expecting an argument
// that we've received when the constructor of the
// derived object was called. We certainly don't want
// to have to rewrite the code that sets the gender, so
// we call the prototype's constructor and pass it what
// it is expecting and allow it to do some of the object
// initialization for us:
Animal.prototype.constructor.call(this, gender);
// Arguments meant for the current constructor are handled
// in the current constructor
this.canFly = canFly
// The inherited properties are available:
console.log("Bird is a " + this.gender + " and it can fly: " + this.canFly);
}
// This just causes Bird to inherit from Animal. This alone
// doesn't cause the Animal constructor to fire when new Bird()
// is executed.
Bird.prototype = Object.create(Animal.prototype);
// By using a different prototype, we have wiped out the native
// constructor so we will reset just the contstructor so that
// constructions of Bird work properly
Bird.prototype.constructor = Bird;
// Just a test to show that making an Animal properly
// requires that the Animal constructor be called and
// passed a gender.
console.log("--- Creating New Animal ---");
var generic = new Animal("male");
// You are explicitly invoking the Bird constructor here.
// It's going to fire that function. That function, in turn,
// is configured to invoke the prototype object's constructor.
// The gender property will be handled by the Animal constructor
// and the canFly will be handled by the Bird constructor.
console.log("--- Creating New Bird ---");
duck = new Bird("female", false);
// ************************************************
function Falcon(gender, canFly, trained){
// We'll pass the arguments needed by the parent object to it
Bird.prototype.constructor.call(this, gender, canFly);
// And set current instance properties right here
this.trained = trained;
console.log("Bird is a " + this.gender + ", can fly: " + this.canFly + " and is trained: " + this.trained);
}
Falcon.prototype = Object.create(Bird.prototype);
// By using a different prototype, we have wiped out the native
// constructor so we will reset just the contstructor so that
// constructions of Falcon work properly
Falcon.prototype.constructor = Falcon;
console.log("--- Creating New Falcon ---");
let f = new Falcon("female", true, false);
You are confusing inheritance with constructor calls. When you say:
duck = new Bird();
you are making an explicit call to the Bird
constructor function so, of course, Bird
will fire.
While Object.create()
is a handy way of causing one object to inherit from another, you still have to manually set up the constructor chain. A good way to understand this is when both constructors take arguments (shown below).
See comments inline:
function Animal(gender) {
// The argument allows the instance property to initialize.
// gender will be a property of Animal and will be inherited
// by anything that inherits from Animal later. But, that
// doesn't change the fact that the Animal constructor
// must be called and passed the gender for the Animal
// to be properly initialized.
this.gender = gender;
// Get the caller of this function (non-standard technique - just used for demo).
// If the caller is null, it means that Animal was called directly. If not,
// we can get the name of the calling function:
var caller = Animal.caller ? Animal.caller.name : "Animal";
// Report of newly constructed Animal
console.log("Animal is a " + this.gender + ". (called by: " + caller + ")");
}
function Bird(gender, canFly) {
// Because a bird inherits from an Animal, you have
// to manually ensure that when a new Bird is created
// the Animal constructor gets called. You can see
// why this is necessary as we have a situation where
// the prototype's constructor is expecting an argument
// that we've received when the constructor of the
// derived object was called. We certainly don't want
// to have to rewrite the code that sets the gender, so
// we call the prototype's constructor and pass it what
// it is expecting and allow it to do some of the object
// initialization for us:
Animal.prototype.constructor.call(this, gender);
// Arguments meant for the current constructor are handled
// in the current constructor
this.canFly = canFly
// The inherited properties are available:
console.log("Bird is a " + this.gender + " and it can fly: " + this.canFly);
}
// This just causes Bird to inherit from Animal. This alone
// doesn't cause the Animal constructor to fire when new Bird()
// is executed.
Bird.prototype = Object.create(Animal.prototype);
// By using a different prototype, we have wiped out the native
// constructor so we will reset just the contstructor so that
// constructions of Bird work properly
Bird.prototype.constructor = Bird;
// Just a test to show that making an Animal properly
// requires that the Animal constructor be called and
// passed a gender.
console.log("--- Creating New Animal ---");
var generic = new Animal("male");
// You are explicitly invoking the Bird constructor here.
// It's going to fire that function. That function, in turn,
// is configured to invoke the prototype object's constructor.
// The gender property will be handled by the Animal constructor
// and the canFly will be handled by the Bird constructor.
console.log("--- Creating New Bird ---");
duck = new Bird("female", false);
// ************************************************
function Falcon(gender, canFly, trained){
// We'll pass the arguments needed by the parent object to it
Bird.prototype.constructor.call(this, gender, canFly);
// And set current instance properties right here
this.trained = trained;
console.log("Bird is a " + this.gender + ", can fly: " + this.canFly + " and is trained: " + this.trained);
}
Falcon.prototype = Object.create(Bird.prototype);
// By using a different prototype, we have wiped out the native
// constructor so we will reset just the contstructor so that
// constructions of Falcon work properly
Falcon.prototype.constructor = Falcon;
console.log("--- Creating New Falcon ---");
let f = new Falcon("female", true, false);
function Animal(gender) {
// The argument allows the instance property to initialize.
// gender will be a property of Animal and will be inherited
// by anything that inherits from Animal later. But, that
// doesn't change the fact that the Animal constructor
// must be called and passed the gender for the Animal
// to be properly initialized.
this.gender = gender;
// Get the caller of this function (non-standard technique - just used for demo).
// If the caller is null, it means that Animal was called directly. If not,
// we can get the name of the calling function:
var caller = Animal.caller ? Animal.caller.name : "Animal";
// Report of newly constructed Animal
console.log("Animal is a " + this.gender + ". (called by: " + caller + ")");
}
function Bird(gender, canFly) {
// Because a bird inherits from an Animal, you have
// to manually ensure that when a new Bird is created
// the Animal constructor gets called. You can see
// why this is necessary as we have a situation where
// the prototype's constructor is expecting an argument
// that we've received when the constructor of the
// derived object was called. We certainly don't want
// to have to rewrite the code that sets the gender, so
// we call the prototype's constructor and pass it what
// it is expecting and allow it to do some of the object
// initialization for us:
Animal.prototype.constructor.call(this, gender);
// Arguments meant for the current constructor are handled
// in the current constructor
this.canFly = canFly
// The inherited properties are available:
console.log("Bird is a " + this.gender + " and it can fly: " + this.canFly);
}
// This just causes Bird to inherit from Animal. This alone
// doesn't cause the Animal constructor to fire when new Bird()
// is executed.
Bird.prototype = Object.create(Animal.prototype);
// By using a different prototype, we have wiped out the native
// constructor so we will reset just the contstructor so that
// constructions of Bird work properly
Bird.prototype.constructor = Bird;
// Just a test to show that making an Animal properly
// requires that the Animal constructor be called and
// passed a gender.
console.log("--- Creating New Animal ---");
var generic = new Animal("male");
// You are explicitly invoking the Bird constructor here.
// It's going to fire that function. That function, in turn,
// is configured to invoke the prototype object's constructor.
// The gender property will be handled by the Animal constructor
// and the canFly will be handled by the Bird constructor.
console.log("--- Creating New Bird ---");
duck = new Bird("female", false);
// ************************************************
function Falcon(gender, canFly, trained){
// We'll pass the arguments needed by the parent object to it
Bird.prototype.constructor.call(this, gender, canFly);
// And set current instance properties right here
this.trained = trained;
console.log("Bird is a " + this.gender + ", can fly: " + this.canFly + " and is trained: " + this.trained);
}
Falcon.prototype = Object.create(Bird.prototype);
// By using a different prototype, we have wiped out the native
// constructor so we will reset just the contstructor so that
// constructions of Falcon work properly
Falcon.prototype.constructor = Falcon;
console.log("--- Creating New Falcon ---");
let f = new Falcon("female", true, false);
function Animal(gender) {
// The argument allows the instance property to initialize.
// gender will be a property of Animal and will be inherited
// by anything that inherits from Animal later. But, that
// doesn't change the fact that the Animal constructor
// must be called and passed the gender for the Animal
// to be properly initialized.
this.gender = gender;
// Get the caller of this function (non-standard technique - just used for demo).
// If the caller is null, it means that Animal was called directly. If not,
// we can get the name of the calling function:
var caller = Animal.caller ? Animal.caller.name : "Animal";
// Report of newly constructed Animal
console.log("Animal is a " + this.gender + ". (called by: " + caller + ")");
}
function Bird(gender, canFly) {
// Because a bird inherits from an Animal, you have
// to manually ensure that when a new Bird is created
// the Animal constructor gets called. You can see
// why this is necessary as we have a situation where
// the prototype's constructor is expecting an argument
// that we've received when the constructor of the
// derived object was called. We certainly don't want
// to have to rewrite the code that sets the gender, so
// we call the prototype's constructor and pass it what
// it is expecting and allow it to do some of the object
// initialization for us:
Animal.prototype.constructor.call(this, gender);
// Arguments meant for the current constructor are handled
// in the current constructor
this.canFly = canFly
// The inherited properties are available:
console.log("Bird is a " + this.gender + " and it can fly: " + this.canFly);
}
// This just causes Bird to inherit from Animal. This alone
// doesn't cause the Animal constructor to fire when new Bird()
// is executed.
Bird.prototype = Object.create(Animal.prototype);
// By using a different prototype, we have wiped out the native
// constructor so we will reset just the contstructor so that
// constructions of Bird work properly
Bird.prototype.constructor = Bird;
// Just a test to show that making an Animal properly
// requires that the Animal constructor be called and
// passed a gender.
console.log("--- Creating New Animal ---");
var generic = new Animal("male");
// You are explicitly invoking the Bird constructor here.
// It's going to fire that function. That function, in turn,
// is configured to invoke the prototype object's constructor.
// The gender property will be handled by the Animal constructor
// and the canFly will be handled by the Bird constructor.
console.log("--- Creating New Bird ---");
duck = new Bird("female", false);
// ************************************************
function Falcon(gender, canFly, trained){
// We'll pass the arguments needed by the parent object to it
Bird.prototype.constructor.call(this, gender, canFly);
// And set current instance properties right here
this.trained = trained;
console.log("Bird is a " + this.gender + ", can fly: " + this.canFly + " and is trained: " + this.trained);
}
Falcon.prototype = Object.create(Bird.prototype);
// By using a different prototype, we have wiped out the native
// constructor so we will reset just the contstructor so that
// constructions of Falcon work properly
Falcon.prototype.constructor = Falcon;
console.log("--- Creating New Falcon ---");
let f = new Falcon("female", true, false);
edited Nov 25 '18 at 18:53
answered Nov 25 '18 at 17:34
Scott MarcusScott Marcus
39.7k52040
39.7k52040
When you set theBird
prototype toBird.prototype = Object.create(Animal.prototype);
what happens toBird.prototype.constructor
? If I want to make a class that inherits fromBird
how do I call it's constructor?
– Mark Meyer
Nov 25 '18 at 18:07
@MarkMeyer When you setBird.prototype = Object.create(Animal.prototype)
, it doesn't mean that when you invokeBird()
thatAnimal()
will fire. It simply means thatBird.prototype
now equalsAnimal.prototype
. And,Bird.prototype.constructor
now equalsAnimal
. But, that's where you are getting confused.Bird.prototype.constructor == Animal
(becauseBird.prototype
isAnimal
), notBird.constructor
. That is stillBird
.
– Scott Marcus
Nov 25 '18 at 18:11
I think you misunderstood me. When you subclass animal you do:Animal.prototype.constructor.call(this, gender)
to set the super's instance variables likegender
. Now lets say I want to make aFalcon
class that inherits fromBird
so in it's constructor I callBird.prototype.constructor.call(this, gender, true)
Does it setcanFly
to true on my Falcon instance? Easy to show in code: repl.it/@ak_mark/GroundedLastEvents The issue is theBird.prototype.constructor
no longer points toBird()
.
– Mark Meyer
Nov 25 '18 at 18:22
All I'm saying is that if I try to subclassBird
the same wayBird
subclassesAnimal
it doesn't work. I'm doing exactly the same thing with Falcon in the repl.it; repl.it/@ak_mark/GroundedLastEvents What am I missing in the repl?
– Mark Meyer
Nov 25 '18 at 18:44
@MarkMeyer I see what you are saying. Yes, swapping theprototype
does become an issue here and the solution is to manually correct theprototype.constructor
after setting the prototype. This works becauseObject.create()
make a new, distinct instance of the prototype object for the sub-object. Changing its constructor won't change it for the entire group - only for derived types. I've updated my answer to show this.
– Scott Marcus
Nov 25 '18 at 18:55
|
show 3 more comments
When you set theBird
prototype toBird.prototype = Object.create(Animal.prototype);
what happens toBird.prototype.constructor
? If I want to make a class that inherits fromBird
how do I call it's constructor?
– Mark Meyer
Nov 25 '18 at 18:07
@MarkMeyer When you setBird.prototype = Object.create(Animal.prototype)
, it doesn't mean that when you invokeBird()
thatAnimal()
will fire. It simply means thatBird.prototype
now equalsAnimal.prototype
. And,Bird.prototype.constructor
now equalsAnimal
. But, that's where you are getting confused.Bird.prototype.constructor == Animal
(becauseBird.prototype
isAnimal
), notBird.constructor
. That is stillBird
.
– Scott Marcus
Nov 25 '18 at 18:11
I think you misunderstood me. When you subclass animal you do:Animal.prototype.constructor.call(this, gender)
to set the super's instance variables likegender
. Now lets say I want to make aFalcon
class that inherits fromBird
so in it's constructor I callBird.prototype.constructor.call(this, gender, true)
Does it setcanFly
to true on my Falcon instance? Easy to show in code: repl.it/@ak_mark/GroundedLastEvents The issue is theBird.prototype.constructor
no longer points toBird()
.
– Mark Meyer
Nov 25 '18 at 18:22
All I'm saying is that if I try to subclassBird
the same wayBird
subclassesAnimal
it doesn't work. I'm doing exactly the same thing with Falcon in the repl.it; repl.it/@ak_mark/GroundedLastEvents What am I missing in the repl?
– Mark Meyer
Nov 25 '18 at 18:44
@MarkMeyer I see what you are saying. Yes, swapping theprototype
does become an issue here and the solution is to manually correct theprototype.constructor
after setting the prototype. This works becauseObject.create()
make a new, distinct instance of the prototype object for the sub-object. Changing its constructor won't change it for the entire group - only for derived types. I've updated my answer to show this.
– Scott Marcus
Nov 25 '18 at 18:55
When you set the
Bird
prototype to Bird.prototype = Object.create(Animal.prototype);
what happens to Bird.prototype.constructor
? If I want to make a class that inherits from Bird
how do I call it's constructor?– Mark Meyer
Nov 25 '18 at 18:07
When you set the
Bird
prototype to Bird.prototype = Object.create(Animal.prototype);
what happens to Bird.prototype.constructor
? If I want to make a class that inherits from Bird
how do I call it's constructor?– Mark Meyer
Nov 25 '18 at 18:07
@MarkMeyer When you set
Bird.prototype = Object.create(Animal.prototype)
, it doesn't mean that when you invoke Bird()
that Animal()
will fire. It simply means that Bird.prototype
now equals Animal.prototype
. And, Bird.prototype.constructor
now equals Animal
. But, that's where you are getting confused. Bird.prototype.constructor == Animal
(because Bird.prototype
is Animal
), not Bird.constructor
. That is still Bird
.– Scott Marcus
Nov 25 '18 at 18:11
@MarkMeyer When you set
Bird.prototype = Object.create(Animal.prototype)
, it doesn't mean that when you invoke Bird()
that Animal()
will fire. It simply means that Bird.prototype
now equals Animal.prototype
. And, Bird.prototype.constructor
now equals Animal
. But, that's where you are getting confused. Bird.prototype.constructor == Animal
(because Bird.prototype
is Animal
), not Bird.constructor
. That is still Bird
.– Scott Marcus
Nov 25 '18 at 18:11
I think you misunderstood me. When you subclass animal you do:
Animal.prototype.constructor.call(this, gender)
to set the super's instance variables like gender
. Now lets say I want to make a Falcon
class that inherits from Bird
so in it's constructor I call Bird.prototype.constructor.call(this, gender, true)
Does it set canFly
to true on my Falcon instance? Easy to show in code: repl.it/@ak_mark/GroundedLastEvents The issue is the Bird.prototype.constructor
no longer points to Bird()
.– Mark Meyer
Nov 25 '18 at 18:22
I think you misunderstood me. When you subclass animal you do:
Animal.prototype.constructor.call(this, gender)
to set the super's instance variables like gender
. Now lets say I want to make a Falcon
class that inherits from Bird
so in it's constructor I call Bird.prototype.constructor.call(this, gender, true)
Does it set canFly
to true on my Falcon instance? Easy to show in code: repl.it/@ak_mark/GroundedLastEvents The issue is the Bird.prototype.constructor
no longer points to Bird()
.– Mark Meyer
Nov 25 '18 at 18:22
All I'm saying is that if I try to subclass
Bird
the same way Bird
subclasses Animal
it doesn't work. I'm doing exactly the same thing with Falcon in the repl.it; repl.it/@ak_mark/GroundedLastEvents What am I missing in the repl?– Mark Meyer
Nov 25 '18 at 18:44
All I'm saying is that if I try to subclass
Bird
the same way Bird
subclasses Animal
it doesn't work. I'm doing exactly the same thing with Falcon in the repl.it; repl.it/@ak_mark/GroundedLastEvents What am I missing in the repl?– Mark Meyer
Nov 25 '18 at 18:44
@MarkMeyer I see what you are saying. Yes, swapping the
prototype
does become an issue here and the solution is to manually correct the prototype.constructor
after setting the prototype. This works because Object.create()
make a new, distinct instance of the prototype object for the sub-object. Changing its constructor won't change it for the entire group - only for derived types. I've updated my answer to show this.– Scott Marcus
Nov 25 '18 at 18:55
@MarkMeyer I see what you are saying. Yes, swapping the
prototype
does become an issue here and the solution is to manually correct the prototype.constructor
after setting the prototype. This works because Object.create()
make a new, distinct instance of the prototype object for the sub-object. Changing its constructor won't change it for the entire group - only for derived types. I've updated my answer to show this.– Scott Marcus
Nov 25 '18 at 18:55
|
show 3 more comments
The statement
Bird.prototype = Object.create(Animal.prototype);
makes the prototype object of the Bird
constructor be a new object whose own prototype is the Animal
prototype, not the Animal
constructor itself.
Thus
duck = new Bird()
makes a new object whose constructor is Bird
, whose prototype is the Bird
prototype, which in turn inherits from the Animal
prototype.
This way, your Animal
prototype could have a method called eat()
, so a call to
duck.eat("fish")
would effectively be a call to the eat()
method on the Animal
prototype. Why? Well there's no "eat" property directly on the duck
object, and none on the Bird
prototype, but there is an "eat" property on the Animal
prototype.
add a comment |
The statement
Bird.prototype = Object.create(Animal.prototype);
makes the prototype object of the Bird
constructor be a new object whose own prototype is the Animal
prototype, not the Animal
constructor itself.
Thus
duck = new Bird()
makes a new object whose constructor is Bird
, whose prototype is the Bird
prototype, which in turn inherits from the Animal
prototype.
This way, your Animal
prototype could have a method called eat()
, so a call to
duck.eat("fish")
would effectively be a call to the eat()
method on the Animal
prototype. Why? Well there's no "eat" property directly on the duck
object, and none on the Bird
prototype, but there is an "eat" property on the Animal
prototype.
add a comment |
The statement
Bird.prototype = Object.create(Animal.prototype);
makes the prototype object of the Bird
constructor be a new object whose own prototype is the Animal
prototype, not the Animal
constructor itself.
Thus
duck = new Bird()
makes a new object whose constructor is Bird
, whose prototype is the Bird
prototype, which in turn inherits from the Animal
prototype.
This way, your Animal
prototype could have a method called eat()
, so a call to
duck.eat("fish")
would effectively be a call to the eat()
method on the Animal
prototype. Why? Well there's no "eat" property directly on the duck
object, and none on the Bird
prototype, but there is an "eat" property on the Animal
prototype.
The statement
Bird.prototype = Object.create(Animal.prototype);
makes the prototype object of the Bird
constructor be a new object whose own prototype is the Animal
prototype, not the Animal
constructor itself.
Thus
duck = new Bird()
makes a new object whose constructor is Bird
, whose prototype is the Bird
prototype, which in turn inherits from the Animal
prototype.
This way, your Animal
prototype could have a method called eat()
, so a call to
duck.eat("fish")
would effectively be a call to the eat()
method on the Animal
prototype. Why? Well there's no "eat" property directly on the duck
object, and none on the Bird
prototype, but there is an "eat" property on the Animal
prototype.
answered Nov 25 '18 at 17:35
PointyPointy
319k44461527
319k44461527
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53470033%2fwhy-constructor-of-a-object-is-executed-even-though-we-change-it-manually-to-ano%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
your assertions are not correct.
– Pointy
Nov 25 '18 at 17:30
Can you tell me the reasons @Pointy
– Tharun26
Nov 25 '18 at 17:31
yes working on it :)
– Pointy
Nov 25 '18 at 17:32
prototype and constructor are different things.
– trincot
Nov 25 '18 at 17:34
1
"When
new Bird()
is executed I expect "Animal" to be logged on console" - Why?Bird
is defined asfunction Bird() { console.log("Bird") }
so that's what you get when calling it.– Bergi
Nov 25 '18 at 17:39