JavaScript __proto__ will affect the original function in the Object? - javascript

The function getBooks has been defined in the Author.prototype. But it can't be used in the Author Object. When I am using the __proto__ to inherits the Person property. Why the does the Author Object have no getBooks function? Is it the effect of __proto__?
function Person(name){
this.name = name;
}
function Author(name,books){
Person.call(this,name);
this.books = books;
}
Person.prototype.getName = function(){
return this.name;
}
Author.prototype.getBooks = function() {
return this.books;
}
var john = new Person('John Smith');
var authors = new Array();
authors[0] = new Author('Dustin Diaz',['JavaScript Design Patterns']);
authors[1] = new Author('Ross Harmes',['JavaScript Design Patterns']);
authors[0].__proto__ = new Person();
console.log(john.getName());
console.log(authors[0].getName());
console.log(authors[0].getBooks())

__proto__ is deprecated. Instead assign the prototype of the class to a new instance of the class you're trying to inherit from before adding new prototype methods to that class.
function Author(name, books) {
Person.call(this, name);
this.books = books;
}
Author.prototype = new Person();
Author.prototype.constructor = Author;
Author.prototype.getBooks = function() {
return this.books;
};
JSFiddle demo: https://jsfiddle.net/bkmLx30d/1/

you've changed the prototype of the object here authors[0].__proto__ = new Person();, so your first Author object in authors now has a prototype that's set to a Person() object .
when you do authors[0].getBooks(), authors[0] will search for getBooks() in the prototype but won't find it since Person.prototype doesn't have a getBooks() and thus give an error.

Related

JS inheritance - MDN article

given MDN JS Inheritance article, we have these lines
My question is, why use Object.create and not just Person.prototype?
I understand the need to link prototypes.
But here is console example rendering the call to Object.create in fact not connecting the inherited methods:
Why is that? is it mistake in the article?
Teacher.prototype = Person.prototype
That sets the prototye of the teachers to the same object as the persons prototype. So if you change that:
Teacher.prototype.hi = () => alert("hi");
Then that exists both on teachers and persons:
new Person().hi();
Thats not what you want when creating a subclass. If you do
Teacher.prototype = Object.create( Person.prototype );
You create a new object that inherits the persons prototype. Now the properties do not exist on the object itself, but they are inherited. That getOwnPropertyNames returns nothing does not mean that the properties are not inherited but the opposite: They just don't exist on the object itself, but on its parent.
new Teacher().greeting(); // works :)
The problem with Teacher.prototype = Person.prototype is that then, there is no actual inheritence going on - both prototypes will reference the same object. If you proceed to add a function to Teacher's prototype, for example getClassTaught(), that will mutate Person.prototype, which should not have that method.
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() { return this.name; };
function Teacher(name, className) {
this.name = name;
this.className = className;
}
Teacher.prototype = Person.prototype;
Teacher.prototype.getClassTaught = function() { return this.className; };
const person = new Person();
console.log('getClassTaught' in person);
You also wouldn't be able to shadow Person functions without replacing them entirely. For example, if there's a greeting() function on Person.prototype, and you assign another greeting() function to Teacher.prototype, you'll be overwriting the function on Person.prototype - other persons calling greeting() may not work anymore, because the function is now Teacher-specific, rather than Person-generic.
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() { return this.name; };
Person.prototype.greeting = function() { return 'Hi, I am ' + this.name; };
function Teacher(name, className) {
this.name = name;
this.className = className;
}
Teacher.prototype = Person.prototype;
Person.prototype.greeting = function() { return 'Hi, I am Teacher ' + this.name; };
const person = new Person('Bob');
console.log(person.greeting());
getOwnPropertyNames only shows you the property names directly on the object itself - it does not show inherited property names. When you use Object.create(Person.prototype), greeting is inherited from the Person prototype; it's not directly on Teacher.prototype, so it doesn't show up in getOwnPropertyNames.

Why constructor is initialised to itself when inheriting

I found the following code for creating inheritance in Javascript in ES5. In this case, Employee is inheriting from Person.
function Employee(name, title) {
Person.call(this, name); // super(name)
this.title = title;
}
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.describe = function() {
return Person.prototype.describe.call(this) // super.describe()
+ ' (' + this.title + ')';
};
I don't understand this line:
Employee.prototype.constructor = Employee;
So Employee is already defined on the first line. Why do we need to create a constructor for it and initialise it to itself? And how does this work?
You're not creating a constructor, just pointing the property constructor at the existing one. If you didn't, it would be misleading because the constructor property inherited by instances created using new Employee would be Person, not Employee:
function Person() {
}
function Employee() {
Person.call(this);
}
Employee.prototype = Object.create(Person.prototype);
var per = new Person();
var emp = new Employee();
console.log(per.constructor === Person); // true
console.log(emp.constructor === Employee); // false?
console.log(emp.constructor === Person); // true?!?!!
Object.create gives you a new object which is linked prototype of Person function. And once you have declared the prototype of Employee, you need to add link constructor property also, thats what is done on line
Employee.prototype.constructor = Employee;

How to get properties of Javascript object prototype?

I'd like to get _firstName and _birthDate from : I tried https://jsfiddle.net/0xLqhufd/
var Person = (function () {
function Person(firstName, birthDate) {
this._firstName = firstName;
this._birthDate = birthDate;
}
return Person;
}());
alert(Object.keys(Person.Prototype));
You cannot get an object's properties before creating a new instance.
Object.keys(new Person)
Also for your understanding, you have properties with your current instance not in prototype. At this moment your prototype will be empty and it inherits the Object's, The core one, that holds toString etc. And those are non enumerable, so you cannot get those by using Object.keys().
DEMO
This is factory function. You need to create instances of the class using new.
var Person = (function () {
function Person(firstName, birthDate) {
this._firstName = firstName;
this._birthDate = birthDate;
}
return Person;
}());
var tushar = new Person('Tushar', '15464');
console.log(tushar); // { _firstName: 'Tushar', _birthDate: '15464' }
You need to create a new person:
var newPerson = new Person('Lars', 'Svensson');
console.log(newPerson.firstname);
console.log(newPerson.birthDate);
This will allow you to access it's properties.

JavaScript returns TypeError when I set the arguments as objects

I want to test inheritance in JavaScript. I made a sample script but it doesn't work. The program returns TypeError.
var Mammal = function(spec) {
this.name = spec.name;
};
Mammal.prototype.get_name = function() {
return this.name;
};
var Cat = function(spec) {
this.name = spec.name;
};
Cat.prototype = new Mammal();
var cat = new Cat({name: 'Mike'});
console.log(cat.get_name());
If I set the arguments of Mammal and Animal functions as non objects, the program runs finely.
The error comes from this line:
Cat.prototype = new Mammal();
The Mammal constructor expects an object, with a name property. You could do:
Cat.prototype = new Mammal({name: null});
Or better yet:
Cat.prototype = Object.create(Mammal.prototype);

call parent ctor from ctor of inheriting class

Is it valid to instead of doing this
function Animal(name, numLegs) {
this.name = name;
this.numLegs = numLegs;
}
Animal.prototype.sayName = function() {
console.log("Hi my name is " + this.name);
};
function Penguin(name) {
this.name = name;
this.numLegs = 2;
}
Penguin.prototype = new Animal();
var penguin = new Penguin("Tux");
penguin.sayName();
do that?
function Animal(name, numLegs) {
this.name = name;
this.numLegs = numLegs;
}
Animal.prototype.sayName = function() {
console.log("Hi my name is " + this.name);
};
function Penguin(name) {
return new Animal(name, 2);
}
Penguin.prototype = new Animal();
var penguin = new Penguin("Tux");
penguin.sayName();
I find the second version more elegant and hoped both version were equivalent in their results, but for the second one codeacademy tells me
Oops, try again. Make sure to create a new Penguin instance called penguin!
while the first one is accepted.
This is not the correct way to call the parent constructor:
function Penguin(name) {
return new Animal(name, 2);
}
The correct way is as follows:
function Penguin(name) {
Animal.call(this, name, 2);
}
The reason is because of the way new works:
Let's say you have a function called ABC.
When you execute new ABC JavaScript creates an instance of ABC.prototype and binds it to this inside of the function ABC which is why you can add properties to this inside ABC.
The constructor function returns this by default unless you return another object explicitly.
The reason Codecademy complains about your code is because you're returning a new Animal(name, 2) which is not an instanceof Penguin.
As I said before the correct way to call the parent constructor is to use ParentConstructor.call(this, arg1, arg2, ...). In this case we are setting the this inside the parent constructor to the same value as this inside the current constructor (which is the instance created by new).
If you want to write elegant code then try this on for size:
function defclass(prototype) {
var constructor = prototype.constructor;
var instance = prototype.instance = function () {};
constructor.prototype = instance.prototype = prototype;
return constructor;
}
function extend(parent, keys) {
var supertype = keys.super = parent.prototype;
var prototype = new supertype.instance;
for (var key in keys) prototype[key] = keys[key];
return defclass(prototype);
}
Using defclass and extend you could rewrite your code as follows:
var Animal = defclass({
constructor: function (name, numLegs) {
this.name = name;
this.numLegs = numLegs;
},
sayName: function () {
console.log("Hi my name is " + this.name);
}
});
var Penguin = extend(Animal, {
constructor: function (name) {
this.super.constructor.call(this, name, 2);
}
});
var penguin = new Penguin("Tux");
penguin.sayName();
How cool is that?
I think the difference is that constructor functions don't return a value. So if you call
new Penguin('bla')
it is not the function Penguin that returns the new Object, it is the new that returns the new Object. So if you let Penguin() return a new Object this will conflict with the new-keyword.
If you want to call the parent-constructor, you can do that as follows:
function Penguin(name) {
Animal.call(this, name, 2);
}
Just additionally: When you assign the prototype of Animal to its sub-prototype Penguin, you call the Function in your example without its paramers. There is a cleaner way to do that:
Penguin.prototype = Object.create(Animal.prototype);
After that you have lost the constructor function of Penguin so you need to reassign it like this:
Penguin.prototype.constructor = Animal;
This is explained in detail here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript
and
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript
In the second example you are NOT returning an instance of Penguin but an instance of Animal. if you want to add more functionality to penguin you need to decorate the Animal class with extra functionality.
function Penguin(name) {
var self = new Animal(name, 2);
self.penguinFunction = function (){
//do something here
}
return self;
}

Categories

Resources