I came across this example while reading the prototype.
function Animal(){
this.name = 'Animal'
}
var animal1 = new Animal();
function Rabbit(){
this.canEat = true;
}
Rabbit.prototype = new Animal();
var r = new Rabbit();
console.log(r.constructor)
And the console is giving me Animal as the output for r.constructor, which is a little confusing as the constructor property should have returned Rabbit as r is created by invoking Rabbit with the new operator.
Also, if I invoke the Rabbit function before assigning the prototype it gives me the desired result.
Objects inherit constructor from their prototype (typically); they get their prototype from the prototype property of the constructor function that creates them when they're created (if they're created by a constructor function). Rabbit.prototype's constructor is incorrect, because of this:
Rabbit.prototype = new Animal();
That calls Animal to create a new instance, and assigns that instance as Rabbit.prototype. So its constructor, inherited from Animal.prototype, is Animal. You've replaced the default object that used to be on Rabbit.prototype (which had constructor set to Rabbit).
In general, that Rabbit.prototype = new Animal() is not the best way to set up inheritance. Instead, you do it like this:
Rabbit.prototype = Object.create(Animal.prototype);
Rabbit.prototype.constructor = Rabbit;
and then in Rabbit:
function Rabbit() {
Animal.call(this); // ***
this.name = "Rabbit"; // Presumably we want to change Animal's deafult
this.canEat = true;
}
Three changes there:
We don't call Animal when setting up the inheritance, we just create a new object that uses Animal.prototype as its prototype, and put that on Rabbit.prototype.
We set constructor on the new object we've assigned to Rabbit.prototype.
We do call Animal when initializing the instance (in Rabbit).
Live Example:
function Animal(){
this.name = 'Animal'
}
var animal1 = new Animal();
function Rabbit() {
Animal.call(this); // ***
this.name = "Rabbit"; // Presumably we want to change Animal's deafult
this.canEat = true;
}
Rabbit.prototype = Object.create(Animal.prototype);
Rabbit.prototype.constructor = Rabbit;
var r = new Rabbit();
console.log(r.constructor);
Or, of course, use ES2015+ class syntax, which handles this plumbing for you (along with a few other benefits).
class Animal {
constructor() {
this.name = "Animal";
}
}
class Rabbit extends Animal {
constructor() {
super();
this.name = "Rabbit";
this.canEat = true;
}
}
const r = new Rabbit();
console.log(r.constructor);
Related
I read that declaring object methods in prototype is good approach because it saves memory and allows to change implementation in any time for all objects.
But what i need to do when i need to set base object for object that uses prototype method declaration?
Example:
function Animal() {
this.age = 0;
this.weight = 0;
//other properties
}
Animal.prototype = {
//some methods for Animal
}
function Dog() {
//properties for Dog
}
Dog.prototype = {
//some methods for Dog
}
So, how can i set Animal as a base class(object) for Dog(because prototype property in Dog is implemented as custom object for methods)?
ES5 version (still most common, but I wouldn't recommend it - see ES6 version)
Based on this post here you need to use Object.create like this:
function Animal() {}
Animal.prototype = {};
function Dog() {}
Dog.prototype = Object.create( Animal.prototype );
Also see this solution with Object.assign (sadly IE doesn't support it)
ES6 version
class Animal {
// all your methods come in here. No more prototype needed.
}
class Dog extends Animal {
}
You can already use ES6 even though most browsers don't completely support it yet. Use babel to transpile you JS.
You could define Animal as a function and use its constructor to set an instance of it in the Dog prototype :
Dog.prototype = new Animal();
More complete code :
var Animal = function () {
this.age = 0;
this.weight = 0;
this.age = function () {
return this.age;
}
// define other methods ...
// ...
return this;
};
var Dog = function () {
// overriding the age
this.age= 10;
// define or override methods ...
// ...
return this;
};
// Dog extends animal
Dog.prototype = new Animal();
// Creating an instance of Dog.
var dog = new Dog();
In this related question, the answer for setting a constructor is like so:
function OldClass() {
alert("old class with incomplete constructor")
}
function ChangedClass(){
alert('new class with same prototype and more complete constructor');
}
ChangedClass.prototype = OldClass.prototype;
var theClassIWant = new ChangedClass();
This is not really setting the constructor, it's making a new object and inheriting the prototype. How can I set the constructor of an Object without changing to a new Object? Is it possible?
P.S. I want something like this:
//non working code
var Foo = function() {}
Foo.prototype.constructor = function(bar_val) {
this.bar = bar_val;
}
var fez = new Foo("cat")
console.log(fez.bar); // outputs: cat;
constructor is a property of the constructor function's prototype, which points to the function itself by default.
When you modify Foo.prototype.constructor, this property points to another function. However, the constructor function Foo remains. So when you create an object, you are still instantiate the constructor function Foo, not the one Foo.prototype.constructor points to.
This is why your code doesn't work. Then let's talk why we need to change the constructor and how to.
In ES5 and before, we take advantage of prototype to simulate a class inheritance mechanism. Which looks like this:
// parent class
function Person(name) {
this.name = name
}
// define parent method
Person.prototype.say = function() {
console.log(this.name)
}
// child class
function Coder(name, major) {
Person.call(this, name) // inherits parent properties
this.job = 'Coding'
this.major = major
}
// inherits properties and methods from parent prototype
Coder.prototype = new Person()
// define child method
Coder.prototype.work = function() {
console.log('I write ' + this.major)
}
// instantiate a child object
var me = new Coder('Leo', 'JavaScript')
console.log(me) // {name: "Leo", job: "Coding", major: "JavaScript"}
Everything looks perfect, but there a problem:
console.log(me.constructor) // Person
What? Isn't me constructed with Coder? Why?
Go back to the first line of this answer, read it again: constructor is a property of the constructor function's prototype.
Originally Coder.prototype.constructor is Coder itself. But with this line: Coder.prototype = new Person(), it got changed. Coder.prototype.constructor now equals Person.prototype.constructor, which is Person.
Well, some would say, try instanceof. Yes, that works:
me instanceof Coder // true
But it's also true for Person, because Coder is a sub class of it:
me instanceof Person // true
This doesn't make sense so we need to fix the constructor problem. That's why we use Coder.prototype.constructor = Coder after Coder.prototype = new Person(), to get back the original constructor.
Full code looks like this:
// parent class
function Person(name) {
this.name = name
}
Person.prototype.say = function() {
console.log(this.name)
}
// child class
function Coder(name, major) {
Person.call(this, name) // inherits parent class
this.job = 'Coding'
this.major = major
}
Coder.prototype = new Person() // inherits parent's prototype
Coder.prototype.constructor = Coder // get back constructor
Coder.prototype.work = function() {
console.log('I write ' + this.major)
}
myClass = {
constructor: function(text){
console.log(text);
}
}
let ob = Object.create(myClass);
ob.constructor("old constructor "); //Output: old constructor
myClass.constructor = function(){
console.log("new constructor ")
}
ob.constructor(); //Output: new constructor
You can do this with every property or function of a class.
Watch this Video here. It explains it perfectly.
I'm going through a JavaScript tutorial and it's asking me to create do the following:
Create a Penguin object with the variable name penguin and any name you'd like.
Then call penguin.sayName();.
My code is as follows:
// the original Animal class and sayName method
function Animal(name, numLegs) {
this.name = name;
this.numLegs = numLegs;
}
Animal.prototype.sayName = function() {
console.log("Hi my name is " + this.name);
};
// define a Penguin class
function Penguin(name) {
this.name = name;
this.numLegs = 2;
};
// set its prototype to be a new instance of Animal
Penguin.prototype = new Animal();
// Here's where I need to create the Penguin object
var penguin = {
name: "Pinguino"
};
penguin.sayName(name);
I'm fairly certain that my code is correct up to where I set the Penguin prototype to the new instance of Animal. However when I submit the code, I get an error saying "Make sure to create a new Penguin instance called penguin!"
With this code:
var penguin = {
name: "Pinguino"
};
You just create an object of class Object.
To create a penguin of type Penguin, instanciate Penguin class:
var penguin = new Penguin("Pinguino");
penguin.sayName();
Here are a couple of improvements to the code:
function Penguin(name) {
// do not copy paste re use your code
// but actually re use it by calling
// the parent constructor
Animal.call(this,name,2);
// this.name = name;
// this.numLegs = 2;
};
// set its prototype to be a new instance of Animal
// Do not create an instance of Parent to set the
// prototype part of inheritance
//Penguin.prototype = new Animal();
Penguin.prototype = Object.create(Animal.prototype);
//when overwriting prototype you will have prototype.constructor
// point to the wrong function, repair that
Penguin.prototype.constructor=Penguin;
More info on constructor functions and prototype here.
I am newbie to Javascript and recently, I faced this question and am curious to know the answer.
function animal(){
// some bse code
}
function cat(){
//some cat code
}
// I know this syntax and works well
cat.prototype= new animal;
and I would like to know the below syntax is correct?
cat c = new animal;
Is it possible in javascript?
(sorry! If the question exists.)
and I would like to know the below syntax is correct?
cat c = new animal;
No, JavaScript variables are always loosely typed, so you don't declare types for them, you just declare them with var (and in ES6, let).
So:
var c = new animal;
Side note #1: In JavaScript, the overwhelming convention is to use an initial capital letter for functions that are intended to be used as constructor functions (e.g., via the new keyword). E.g., Animal and Cat, not animal and cat.
Side note #2: About this:
// I know this syntax and works well
cat.prototype= new animal;
That's a common, but poor, practice. Here's how to do that correctly:
cat.prototype = Object.create(animal.prototype);
cat.prototype.constructor = cat;
...and then in cat, as the first thing:
animal.call(this);
Complete example with updated capitalization:
function Animal() {
}
function Cat() {
Animal.call(this);
// ...add Cat-level initialization here
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
About Object.create: It's an ES5 function that creates an object with a specific underlying prototype. The proper ES5 version takes two arguments, and what it does with the second argument cannot be shimmed on older browsers. But for what we're doing, we only need the first argument, which can be shimmed on older browsers:
if (!Object.create) {
Object.create = function(proto, props) {
if (typeof props !== "undefined") {
throw "Object.create shims cannot implement the second argument.";
}
function ctor() { }
ctor.prototype = proto;
return new ctor();
};
}
So why is Cat.prototype = new Animal; poor practice? Well, what if Animal takes per-instance arguments? Consider:
function Animal(age) {
this.age = age;
}
What would we give for age in the Cat.prototype = new Animal(???); line?
Answer: We don't. We shouldn't call Animal, which is a constructor function for instances, until we're constructing an instance. Instead, we create a new object for the Cat.prototype property, and give that new object Animal.prototype as its prototype.
Complete example:
function Animal(age) {
this.age = age;
}
function Cat(age, color) {
Animal.call(this, age);
this.color = color;
}
Cat.prototype = Object.create(Animal.prototype);
Cat.prototype.constructor = Cat;
var c = new Cat(14, "Tabby");
No, it is not. In JavaScript you can't declare the type of a variable. The type of a variable is the type of its current value, so
var c = new animal(); //correct
but
cat c = new animal(); //parse error.
I have problem with inheritance of consturctor:
function Alive(name) {
this.name = name;
}
var Cat = new Function();
Cat.prototype = new Alive();
Cat.prototype.constructor = Alive;
var cat = new Cat('Thomas');
alert(cat.name);
alert show undefined. What i do wrong? jsfiddle
Looks like you want the parent constructor to get called automatically, that's not supported without some extra work. Your code should look like the following
function Alive(name) {
this.name = name;
}
function Cat(name) {
// Call the parent constructor
Alive.call(this, name);
}
Cat.prototype = new Alive();
// This line is to fix the constructor which was
// erroneously set to Alive in the line above
Cat.prototype.constructor = Cat;
var cat = new Cat('Thomas');
alert(cat.name);
If you use a library to implement inheritance, you don't have to worry about this. They can even call your parent constructor automatically if you don't want to create an empty constructor. The above code is still not ideal. See a post I wrote that talks about the 'right' way to do inheritance. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html
Because Cat doesn't accept an argument. Here's what you want:
function Alive(name) {
this.name = name;
}
function Cat(name) {
Alive.call(this, name);
}
// since there's nothing on the prototype, this isn't necessary.
// Cat.prototype = new Alive();
var cat = new Cat('Tomas');
alert(cat.name);