My proto reference of "mike" instance points to "Student" but as its name shows "Person" , I don't know why is that. Here is my code and screenshot of console below:
const Person = function (firstName,birthYear) {
this.firstName = firstName;
this.birthYear = birthYear;
}
Person.prototype.calcAge = function () {
console.log(2037 - this.birthYear);
}
const Student = function (firstName, birthYear, course){
Person.call(this,firstName,birthYear);
this.course = course;
};
Student.prototype = Object.create(Person.prototype)
Student.prototype.constructor = Student;
Student.prototype.introduce = function () {
console.log(`My name is ${this.firstName} and ,I study ${this.course}`);
}
const mike = new Student('Mike',2020, 'Computer Science');
console.log(mike);
When I check on console it shows Person:
Student.prototype = Object.create(Person.prototype)
In this case, you are creating a new object and make it the value of Student.prototype. The new object Student has Person.prototype as its prototype.
The very first thing you see in Chrome's console is Student. That is the "type" of your mike object.
On the other hand, the __proto__ property of mike references the prototype from which this instance was created. Your code has explicitly defined that prototype with the following statement:
Student.prototype = Object.create(Person.prototype);
So, from that moment on, Student.prototype instanceof Person is true, but Student.prototype instanceof Student false. And all instances created with new Student, will reference the Student.prototype in their __proto__ property. So what you see is as expected.
The fact that the following assignment was made, doesn't change this behaviour:
Student.prototype.constructor = Student;
This is a cosmetic change, and doesn't determine the nature of the instances that Student creates. That might have mislead you.
class syntax
The code you provided performs the steps needed to set up a prototype chain, where a Student inherits from a Person.
In modern JavaScript it is much less cryptical to make this happen. Nowadays you would write this example as follows:
class Person {
constructor(firstName,birthYear) {
this.firstName = firstName;
this.birthYear = birthYear;
}
calcAge() {
console.log(2037 - this.birthYear);
}
}
class Student extends Person {
constructor(firstName, birthYear, course) {
super(birthYear, course);
this.course = course;
}
introduce() {
console.log(`My name is ${this.firstName} and ,I study ${this.course}`);
}
}
const mike = new Student('Mike',2020, 'Computer Science');
console.log(mike);
The result in the console will also here confirm that the prototype object of a Student instance is an instance of Person (not of Student).
Related
// Parent class
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log("Hello. My name is " + this.name);
};
Person.prototype.sayGoodbye = function() {
console.log("Goodbye!");
};
// Child class
function Student(name, gpa) {
Person.call(this, name);// I'm confused what does keyword 'this' refer to?
this.gpa = gpa;
}
// create child object
let john = new Student("john",3.5);
Does the keyword 'this' refer to object john or Person.prototype?
The new operator preceding Student("john",3.5); creates a new instance object, prototyped on the following function's prototype property, before calling the function with the newly created object as its this value. ( Refer to new operator documentation on MDN for more detail).)
So the this in
Person.call(this, name);
is the student object created and returned by new before being stored in the john variable.
Student code then calls the Person function with its own this value so that the Person constructor can add "Person" type properties to the Student object before returning from Student.
Worth noting:
The example shows how the construction of class objects was undertaken before implementation of the class keyword in JavaScript
This particular example does not implement inheritance of Person.prototype properties by Student objects. This was sometime implemented using a dummy Person object as the prototype of Student, using code similar to:
Student.prototype = new Person();
Student.prototype.constructor = Student;
The shortcomings and limitations of this practice at least contributed to the introduction of class constructor functions in ECMAScript.
Here to make Student a child class you need to extend it to the Person class:
class Person {
var name;
constructor(name) {
this.name = name;
}
sayhello(){
console.log("Hello. My name is " + this.name);
}
sayGoodbye(){
console.log("Goodbye!");
}
}
class Student extends Person {
getName(){
return this.name;
}
}
student = new Student("Jhon");
The 'this' keywords refers to the current object. You can call methods of the parent class from the child class using the child class object itself as you are using extend keywords.
This is a simple example of inheritance.
This question already has answers here:
Benefits of using `Object.create` for inheritance
(4 answers)
Closed 2 years ago.
Is there any difference the following code as to prototype assignments. If so, can I learn?
function Person(name, lastname)
{}
Person.prototype.school = `GTU`
function Student(name, lastname) {
this.name = name
this.lastname = lastname
}
Student.prototype = Person.prototype // <-----
Student.prototype = Object.create(Person.prototype) // <-----
Student.prototype = new Person() // <-----
//Student.prototype.constructor = Student
const me = new Student(`a`, `b`)
console.log(me);
Yes, there are significant differences.
This replaces the Student.prototype property's value with the value of Person.prototype:
Student.prototype = Person.prototype // <-----
This replaces the Student.prototype property's value with a new object that uses Person.prototype as its prototype:
Student.prototype = Object.create(Person.prototype) // <-----
(If doing inheritance chains via constructor functions in ES5 and below, that's usually what you want.)
This creates a new object using Person.prototype as its prototype, but also calls the Person constructor to initialize it:
Student.prototype = new Person() // <-----
That's not usually want you want, because you're not creating a Person instance, you're setting up a chain of constructor functions.
As a side note, after you do what you usually want to do:
Student.prototype = Object.create(Person.prototype) // <-----
you also want to do this:
Object.defineProperty(Student.prototype, "constructor", {
value: Student,
writable: true,
configurable: true
});
since otherwise, the constructor property will be inherited with its standard value (Person), which isn't appropriate for the prototype object that will be assigned to Student objects. More details about that in my answer here, but fundamentally, to set up the chain in ES5 you'd do this:
function Person(name, lastname) {
// Since you're accepting these as parameters, you probably want to store them
this.name = name;
this.lastname = lastname;
}
Person.prototype.school = `GTU`;
function Student(name, lastname, studentNumber) {
// Since `Student` derives from `Person`, let `Person` do its initialization
Person.call(this, name, lastname);
// Here we do `Student`-specific initialization
this.studentNumber = studentNumber;
}
// Set up `Student` as a subclass of `Person`
Student.prototype = Object.create(Person.prototype);
Object.defineProperty(Student.prototype, "constructor", {
value: Student,
writable: true,
configurable: true
});
// Example of using `Student`:
const me = new Student(`a`, `b`, 1234);
console.log(me);
I've added a Student-level property (studentNumber) to that to emphasize where each set of properties should be initialized.
In ES2015+, if you're going to use constructor functions to set up inheritance chains, there's basically no reason not to use class syntax. (But only if you're using constructor functions to set up inheritance chains; JavaScript has other paradigms you can use, you don't have to use constructor functions.) That would look like this:
class Person {
constructor(name, lastname) {
// Since you're accepting these as parameters, you probably want to store them
this.name = name;
this.lastname = lastname;
}
// Before too long, you'll be able to replace the assignment that's after the
// `class` with the following:
// static school = `GTU`;
}
Person.prototype.school = `GTU`;
class Student extends Person {
constructor(name, lastname, studentNumber) {
// Let `Person` do its initialization
super(name, lastname);
// Here we do `Student`-specific initialization
this.studentNumber = studentNumber;
}
}
// Example of using `Student`:
const me = new Student(`a`, `b`, 1234);
console.log(me);
I'm trying to understand what actually happens when you create a new instance of a class with ES6. As far as I can tell, a new instance is created with properties as defined in the constructor and then the rest of the methods in the class are actually properties on the prototype object
For example
class Dog {
constructor(name){
this.name = name
}
speak (){
console.log('Woof')
}
}
Would be the equivelant to
function Dog(name){
this.name = name;
}
Dog.prototype.speak = function () {
console.log('Woof');
}
In the class example. If I create an instance of my Dog class, Is the prototype of that method pointing to the Dog class itself or is it a completely new object? Because when I Object.getPrototypeOf(myDog) it returns Dog {}.
They are functionally exactly the same. Here are some interesting properties about prototypes and classes to point out though:
class Dog1 {
constructor(name){
this.name = name
}
speak (){ // adds speak method to the prototype of Dog1
console.log('Woof')
}
}
Dog1.prototype.speak = () => { // overwrites speak method to the prototype of Dog1
console.log('Different Woof');
}
console.log(typeof Dog1); // Class keyword is just syntactic sugar for constructor function
const newDog = new Dog1('barkie');
newDog.speak();
/////////////////////////////
function Dog2(name){
this.name = name;
}
Dog2.prototype.speak = () => {
console.log('Woof');
}
const aDog = new Dog2('fluffy');
aDog.__proto__.speak(); // the __proto__ property references the prototype
aDog.speak(); // the __proto__ property is not necessary, it will automatically climb the protochain if the property is not found on the object itself.
I left some comments in order to point out the quirks which can be a bit hard to grasp. I you have any further questions about it you can leave a comment. Hopefully this is helpful to you.
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.
I have a couple of questions about the code.
1) In the student constructor, does Person.call(this, firstName) give student access to the methods of person? or does it change the context of this?
2) I assume Student.prototype = Object.create(Person.prototype) gives us acess to the methods and properties of person?
I'm having a hard time understanding the call method.
var Person = function(firstName) {
this.firstName = firstName;
};
Person.prototype.walk = function(){
console.log("I am walking!");
};
function Student(firstName, subject) {
Person.call(this, firstName);
this.subject = subject;
};
Student.prototype = Object.create(Person.prototype); // See note belo
Student.prototype.constructor = Student;
Student.prototype.sayHello = function(){
console.log("Hello, I'm " + this.firstName + ". I'm studying "
+ this.subject + ".");
};
1) No, it sets the this value and passes an argument, but as it sets the this value of Person to whatever this is inside Student, it could also give Person access to Student, but not the other way around.
All call(this-value, [arg1,arg2]) and apply(this-value, [[arg1,arg2]]) does, is call the function with a given this-value, and arguments.
2) Yes, Student.prototype = Object.create(Person.prototype) copies the prototype of Person and sets it as the prototype of Student, giving Student the same prototyped methods as Person, but a copy, not the same reference.