How Do I Call An Inherited JavaScript Constructor With Parameters? - javascript

Greetings,
After reading the following article I have a question:
https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript
In the inheritance example, the Person constructor doesn't take any parameters. How would this same example look if I were to add one and call it from the Student constructor?
Thanks!

Well, a way that you can re-use the logic of the Person constructor is invoking it with call or apply, for example:
function Person(gender) {
this.gender = gender;
}
function Student(gender) {
Person.apply(this, arguments);
}
Student.prototype = new Person(); // make Student inherit from a Person object
Student.prototype.constructor = Student; // fix constructor property
var foo = new Student('male');
foo.gender; // "male"
foo instanceof Student; // true
foo instanceof Person; // true
If you want to prevent the execution of the Person constructor when is called without arguments (like in the line: Student.prototype = new Person();), you can detect it, e.g.:
function Person(gender) {
if (arguments.length == 0) return; // don't do anything
this.gender = gender;
}

Accepted answer seems to be incorrect. Based on what Mozilla says about OO JavaScript, correct way to do it is:
var Person = function(firstName) {
this.firstName = firstName;
};
function Student(firstName, subject) {
// Call the parent constructor, making sure (using Function#call)
// that "this" is set correctly during the call
Person.call(this, firstName);
// Initialize our Student-specific properties
this.subject = subject;
};
// Create a Student.prototype object that inherits from Person.prototype.
// Note: A common error here is to use "new Person()" to create the
// Student.prototype. That's incorrect for several reasons, not least
// that we don't have anything to give Person for the "firstName"
// argument. The correct place to call Person is above, where we call
// it from Student.
Student.prototype = Object.create(Person.prototype); // See note below
// Set the "constructor" property to refer to Student
Student.prototype.constructor = Student;
// Example usage:
var student1 = new Student("Janet", "Applied Physics");
As you can clearly see, Mozilla specifies that it is a common error to use "new Person()" to create the Student.prototype. Hence accepted answer is misleading.
I have actually tested this in my ongoing project and Mozilla's way is correct, while above answer does not work.

// define the Person Class
function Person(name) {
this.personname = name;
}
Person.prototype.walk = function(){};
Person.prototype.sayHello = function(){
alert (this.personname );
};
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/constructor
The full code:
<script>
// define the Person Class
function Person(name) {
this.personname = name;
}
Person.prototype.walk = function(){};
Person.prototype.sayHello = function(){
alert (this.personname );
};
// define the Student class
function Student() {}
// inherit Person
Student.prototype = new Person("test");
// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;
// replace the sayHello method
Student.prototype.sayHello = function(){
alert('hi, I am a student and my name is \'' + this.personname + '\'' );
}
// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
alert('goodBye');
}
var student1 = new Student();
student1.sayHello();
student1.sayGoodBye();
</script>

By all other comments I created an example which works for me. Since I did not use prototype explicitly I hope I am not missing an important point.
// variable for tracking instantiations and checking the uniqueness of the objects
var instances = 0;
var Generic = function() {
this.instanceId = ++instances;
this.toString = function() {return 'Generic [iid='+ this.instanceId +']'};
console.log('constructor-invoke: Generic ('+ this.instanceId +')');
};
var SpecificName = function(inName) {
Generic.call(this);
this.getName = function() { return inName; };
var superToString = this.toString.bind(this); // binds the inner function 'this' to this SpecificName instance
this.toString = function() {
return 'SpecificName [iid='+ this.instanceId +', name='+ this.getName() +', super.toString='+ superToString() +']'
}
console.log('constructor-invoke: SpecificName ('+ this.instanceId +')');
};
var SpecificNames = function(inFirstName, inLastName) {
SpecificName.call(this, inLastName +', '+ inFirstName );
var superToString = this.toString.bind(this);
this.toString = function() {
return 'SpecificNames [iid='+ this.instanceId +', name='+ this.getName() +', super.toString='+ superToString() +']'
}
console.log('constructor-invoke: SpecificNames ('+ this.instanceId +')');
};
var g = new Generic();
var sn = new SpecificName('Run Forest Run');
var sns = new SpecificNames('Forest','Gump');
console.log('g: '+ g.toString());
console.log('sn: '+ sn.toString());
console.log('sns: '+ sns.toString());
leads to this output:
constructor-invoke: Generic (1)
constructor-invoke: Generic (2)
constructor-invoke: SpecificName (2)
constructor-invoke: Generic (3)
constructor-invoke: SpecificName (3)
constructor-invoke: SpecificNames (3)
g: Generic [iid=1]
sn: SpecificName [iid=2, name=Run Forest Run, super.toString=Generic [iid=2]]
sns: SpecificNames [iid=3, name=Gump, Forest, super.toString=SpecificName [iid=3, name=Gump, Forest, super.toString=Generic [iid=3]]]

Related

How to use constructors as a prototype chain?

Suppose that I have a javascript constructor:
function Person(name) {
this.name = name;
this.hello = function () { return "It's a-me, " + name + "!"; };
}
the Person "type" has a convenient method, hello that I would like to re-use on another type Student. I would like for a Student to have the following structure:
function Student(name) {
this.name = name;
this.hello = function () { return "It's a-me, " + name + "!"; };
this.books = [];
}
One option is to use the code for Student as-is above. This is sub-optimal for the usual reasons, such as that if I want it to mirror the Person type, then I have to manually keep their code in sync. Anyway, this is not good.
A second option (from this answer) is to do something like:
function Student(name) {
Person.call(this, name);
this.books = [];
}
When I mario = new Student("mario") I get the following:
Object { name: "mario", hello: hello(), books: [] }
I've successfully achieved the inheritance that I wanted, but this has the unfortunate property of placing all of the desired properties into my object. Notably, for example, there is a "hello" property on mario. It would be nice if that "hello" property could be looked up in the prototype chain.
How can I neatly create a prototype chain given the relevant object constructors?
When you create an object with new, the this value of your constructor function is set to the object, and that object's prototype is set to the prototype of the constructor Function being called.
That's why your properties are currently being added to the created object.
function Student {
this.name = name
}
const student = new Student('John')
// is (almost) equivalent to the following
const student = {}
student.name = 'John'
But if you want to add properties to the prototype instead, so that you can use inheritance, then in ES5 Javascript you can do so by assigning properties directly to the prototype of your constructor function.
function Person(name) {
this.name = name;
}
// Person is a function
// Its prototype is an instance of Object, and it has no properties
// i.e. something like Person.prototype = new Object()
Person.prototype.hello = function() {
return 'It is I, ' + this.name
}
// Now Person.prototype has one property, "hello", which is a function.
function Student(name) {
Person.call(this, name)
this.books = [];
}
// Student is a function
// Its prototype is also an instance of Object with no properties
// the following is the magic line
Student.prototype = Object.create(Person.prototype)
// We replace the prototype of the Student function with a new object, but
// Object.create() allows us to set the prototype to an existing object, in this case Person.prototype,
// Person.prototype is itself an instance of Object, and we previously
// added the "hello" function to it as a property.
const student = new Student('John')
// So what happens here?
// First a new object is created, and its prototype is set to Student.prototype
// Then we call Person.call(this)
// Which executes the body of the Person function
// So you get the properties on the object itself through the body of the Person and Student functions
// And you get the shared functionality through the prototype chain of instance -> Student.prototype -> Person.prototype -> Object.prototype
Hope that helps!
You can use prototyping method or class sugar method as you want.
Here is a simple example :
function Student(name) {
this.name = name;
this.books = [];
}
Student.prototype.hello = function(){
return "It's a-me, " + this.name + "!";
}
Student.prototype.addBook = function(book){
this.books.push(book);
}
Student.prototype.getBooks = function(){
return this.books;
}
let mario = new Student("Mario");
console.log(mario.hello());
mario.addBook("prototyping");
mario.addBook("chain");
console.log(mario.getBooks());
class Person {
constructor(name) {
this.name = name;
this.books = [];
}
hello(){
return "It's a-me, " + this.name + "!";
}
addBook(book){
this.books.push(book);
}
getBooks(){
return this.books;
}
}
let luigi = new Person("Luigi");
console.log(luigi.hello());
luigi.addBook("classSugar");
luigi.addBook("classType");
console.log(luigi.getBooks());
For longer chains use Object.assign, here is an example of making a GradStudent that is both a Student and a Person and has the personality of a Comedian and also has the properties and methods of a 4th class GameCharacter:
(function() {
//Person
function Person(name) {
this.name = name;
this.helloString = "Hello my name is "
}
Person.prototype.name = "Bob";
Person.prototype.hello = function() {
return this.helloString + this.name;
};
//Student
function Student(name, books) {
Person.call(this, name);
this.books = books;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
Student.prototype.books = ["math","reading"];
//Comedian
function Comedian(name) {
Person.call(this,name);
};
Comedian.prototype = Object.create(Person.prototype);
Comedian.prototype.constructor = Comedian;
Comedian.prototype.hello = function() {
return "I don't know what my parents where thinking when they name me Squat, just kidding, my name is " + this.name;
};
//GameCharacter
function GameCharacter(power) {
this.power = power;
};
GameCharacter.prototype = new Object();
GameCharacter.prototype.constructor = GameCharacter;
GameCharacter.prototype.gainPower = function(power) {
this.power += ", "+power;
};
GameCharacter.prototype.statePower = function() {
return this.power;
};
//GradStudent
function GradStudent(name, books, degree) {
Comedian.call(this, name);
Student.call(this,name,books);
GameCharacter.call(this, "jumping");
this.degree = degree;
this.gainPower("flying");
}
GradStudent.prototype = Object.create(Student.prototype);
Object.assign(GradStudent.prototype, Comedian.prototype, GameCharacter.prototype);
GradStudent.prototype.constructor = GradStudent;
var gradStudent = new GradStudent("Bill",["C", "C++", "JavaScript"], "B.S.");
console.log(gradStudent.hello() + " I have a " + gradStudent.degree +" I am studying " + gradStudent.books.toString() + ". \n In a game I play my power's are "+ gradStudent.statePower() + ". \n Is gradStudent also a Student? " + (gradStudent instanceof Student) + "" );
var otherStudent = new Student("Jennifer" ,["english", "science"]);
console.log(gradStudent.books.toString() + " " + otherStudent.books.toString());
})();
GradStudent is an instance of Student, it's a type of Student, and can also do all the things Comedian and GameCharacter does. The value of Object.assign is that kind of multiple inheritance.
I can accomplish such a thing with the following:
function Student(name) {
Object.setPrototypeOf(this, new Person(name));
this.books = [];
}
However, I'm not familiar enough with javascript to know what possible problems might arise with this solution. Coming from other OO style languages, it feels weird for the prototype of mario to be an actual instance of a Person, but I suppose everything in js is an instance, in some sense, so this might just be bias on my part.

Javascript prototype methods vs object methods [duplicate]

When using a constructor function in JavaScript to create a class, is it possible to redefine the class's method later?
Example:
function Person(name)
{
this.name = name;
this.sayHello = function() {
alert('Hello, ' + this.name);
};
};
var p = new Person("Bob");
p.sayHello(); // Hello, Bob
Now I'd like to redefine sayHello like this:
// This doesn't work (creates a static method)
Person.sayHello() = function() {
alert('Hola, ' + this.name);
};
so when I create another Person, the new sayHello method will be called:
var p2 = new Person("Sue");
p2.sayHello(); // Hola, Sue
p.sayHello(); // Hello, Bob
EDIT:
I realize I could send in an argument like "Hello" or "Hola" to sayHello to accomplish the different output. I also realize I could simply assign a new function to p2 like this:
p2.sayHello = function() { alert('Hola, ' + this.name); };
I'm just wondering if I can redefine the class's method so new instances of Person will use the new sayHello method.
is it possible to redefine the class's method later?
Yes. However, you must not assign the new function to a property of the Person constructor, but to the instance itself:
var p2 = new Person("Sue");
p2.sayHello(); // Hello, Sue
p2.sayHello = function() {
alert('Hola, ' + this.name);
};
p2.sayHello(); // Hola, Sue
If you want to do this for all new instances automatically (and have not used the prototype for the method, which you easily could exchange as in #dystroy's answer), you will need to decorate the constructor:
Person = (function (original) {
function Person() {
original.apply(this, arguments); // apply constructor
this.sayHello = function() { // overwrite method
alert('Hola, ' + this.name);
};
}
Person.prototype = original.prototype; // reset prototype
Person.prototype.constructor = Person; // fix constructor property
return Person;
})(Person);
To have a different function for p2, you can just set the sayHello property of p2 :
p2.sayHello = function(){
alert('another one');
}
p2.sayHello();
If you use prototype, then you can also change it for all instances of Person (and still you can overwrite it for a specific person) :
function Person(name)
{
this.name = name;
};
Person.prototype.sayHello = function() {
alert('Hello, ' + this.name);
};
var p = new Person("Bob");
// let's set a specific one for p2
p2.sayHello = function(){
alert('another one');
}
// now let's redefine for all persons (apart p2 which will keep his specific one)
Person.prototype.sayHello = function(){
alert('different!');
}
p.sayHello(); // different!
p2.sayHello(); // another one
To solve your issue You can use Reflect object
class Person {
public name: string;
constructor(name: string) {
this.name = name;
}
public sayHello(): void {
console.log(`Hello, ${this.name}`)
}
}
const p = new Person("Bob");
p.sayHello(); // Hello, Bob
Reflect.defineProperty(Person.prototype, 'sayHello', { value: function() {
console.log(`Goodbye, ${this.name}`)
}})
p.sayHello(); // Goodbye, Bob

Adding to the prototype of an instance of another prototype: JavaScript

My question is simply:
How do I set up the prototype of a class that inherits from another class's prototype?
My code below works until I try to call Pierre.mySkill(), at which point the console says that the function is undefined.
My reason for this, theoretically, is to be able to create instances of Pirault, and also instances of Person, and be able to add to Pirault's prototype without having to add to Person's.
function Person (name, age){
this.name = name;
this.age = age;
}
Person.prototype.info = function(){
console.log('I am '+this.name+' and I am '+this.age+' years old.');
};
function Pirault (){
this.skill = arguments[2];
Person.apply(this, arguments);
}
Pirault.prototype.mySkill = function(){
console.log('My skill is '+this.skill);
}
Pirault.prototype = Object.create(Person.prototype);
Pirault.prototype.constructor = Pirault;
var Pierre = new Pirault('Pierre', 30, 'Programming');
Organize your code so that all the prototype methods are defined after the prototype object is created. For example:
Pirault.prototype = Object.create(Person.prototype);
Pirault.prototype.constructor = Pirault;
Pirault.prototype.mySkill = function(){
console.log('My skill is '+this.skill);
}
Demo. As it stands, you correctly define a method on the prototype - but then lose it, when an object (created by Object.create) becomes a new Pirault.prototype.
As an alternative approach you don't need constructors to do this. All you need in modern browsers are objects and Object.create:
var Person = {
info: function() {
console.log('I am '+ this.name +'and I am '+ this.age +' years old.')
}
}
var Pirault = Object.create(Person)
Pirault.mySkill = function() {
console.log('My skill is '+ this.skill)
}
var pierre = Object.create(Pirault)
pierre.name = 'Pierre'
pierre.age = 30
pierre.skill = 'Programming'
pierre.mySkill() //=> My skill is Programming
console.log(Pirault.isPrototypeOf(pierre)) //=> true
console.log(Person.isPrototypeOf(pierre)) //=> true

why do we need to call the parent constructor in JavaScript Inheritance

I am experimenting with JavaScript Inheritance. Basically, I am following this tutorial.
I see that, with the code there, the Person class is instantiated twice. Please have a look at this fiddle.
What I did is comment out:
Person.call(this)
And the inheritance is working just fine.
In the original code, the line
Person.call(this)
is used. Is there a need of calling parent constructor with child scope?
Could you please also give some explanation, I am new to OO JavaScript.
Thanks a lot.
EDIT:
My code in the fiddle is as follows:
function Person(gender) {
this.gender = gender;
document.write('Person instantiated</br>');
}
Person.prototype.walk = function(){
document.write("is walking</br>");
};
Person.prototype.sayHello = function(){
document.write("Hello</br>");
};
Person.prototype.sayGender = function(){
document.write(this.gender + "</br>");
};
function Student() {
//Person.call(this);
document.write('Student instantiated</br>');
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
Student.prototype.sayHello = function(){
document.write("Student says Hello</br>");
}
Student.prototype.sayGoodBye = function(){
document.write("Student says goodbye</br>");
}
var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();
document.write(student1 instanceof Person);
document.write("</br>");
document.write(student1 instanceof Student);
Yes, you will need it. In your example, all Students have the same gender and there will be only one Person instantiated, regardless of the number of instantiated Students.
Better would be:
function Student() {
// gives this Student properties of one (new) Person:
Person.call(this);
document.write('Student instantiated</br>');
}
// does not create a Person, just makes Students have Person prototype features
Student.prototype = Object.create(Person.prototype);
Running the example you provided only calls the Person() constructor once during initial execution of the script when the line "Student.prototype = new Person();" is executed.
If we modify your script to create a second student and separate the setup from the instantiation: bit: http://jsfiddle.net/anacW/
function Person(gender) {
this.gender = gender;
document.write('Person instantiated</br>');
}
Person.prototype.walk = function(){
document.write("is walking</br>");
};
Person.prototype.sayHello = function(){
document.write("Hello</br>");
};
Person.prototype.sayGender = function(){
document.write(this.gender + "</br>");
};
function Student() {
//Person.call(this);
document.write('Student instantiated</br>');
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
Student.prototype.sayHello = function(){
document.write("Student says Hello</br>");
}
Student.prototype.sayGoodBye = function(){
document.write("Student says goodbye</br>");
}
document.write("*** Building student1 *** </br>");
var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();
document.write("*** Building student2 ***</br>");
var student2 = new Student();
student2.sayHello();
student2.walk();
student2.sayGoodBye();
document.write("*** InstanceOf Tests ***</br>");
document.write("student1 is Person?: " + (student1 instanceof Person));
document.write("</br>");
document.write("student1 is Student?: " + (student1 instanceof Student));
document.write("</br>");
document.write("student2 is Person?: " + (student2 instanceof Person));
document.write("</br>");
document.write("student2 is Student?: " + (student2 instanceof Student));
​
This code gives:
Person instantiated
*** Building student1 ***
Student instantiated
Student says Hello
is walking
Student says goodbye
*** Building student2 ***
Student instantiated
Student says Hello
is walking
Student says goodbye
*** InstanceOf Tests ***
student1 is Person?: true
student1 is Student?: true
student2 is Person?: true
student2 is Student?: true
Which shows you that the Person constructor is only being called once, and is never called by instantiating a Student. This might be desirable in your case (I don't know enough javascript to tell you whether it's 'proper' form or not).
Here how I do this:
Foo = function() {}
Foo.prototype.sayHello = function() { console.log("hello"); }
Bar = function() {}
Bar.prototype = new Foo();
Bar.prototype.sayBye = function() { console.log("bye"); }
var oBar = new Bar();
oBar.sayHello(); // "hello"
oBar.sayBye(); // "bye"

Javascript inheritance question

Why Version 2 in the code below does not produce the same result as Version 1 ?
function person(name) {
this.name = name;
}
function student(id, name) {
this.id = id;
// Version 1
//this.inherit_from_person = person;
//this.inherit_from_person(name);
// Version 2
person(name);
}
s = new student(5, 'Misha');
document.write(s.name); // Version 1 => Misha
// Version 2 => undefined
Live demo here.
When you call person(name) it gets called with this bound to the global object, so that's just setting window.name = "Misha". You want person.call(this, name) to explicitly bind it to the right this.
It looks to me like you are trying to implement prototype inheritance. Below is a classic example, though not much used. Complex inheritance is just not needed in javascript, usually a single instance is all that is required. If multiple instances are required, the module pattern can be used with closures for shared methods and properties and also to provide private and priveliged members.
// Person is the "base class"
function Person(name) {
this.setName(name);
}
// Use setters and getters so properties are
// added appropriately.
Person.prototype.setName = function(name) {
this.name = name;
}
// Add Person methods
Person.prototype.getName = function() {
return this.name;
}
// Student inherits from Person and also has
// its own methods
function Student(name, id) {
this.setId(id);
this.setName(name);
}
// To inherit from Person, Student.prototype should
// be an instance of Person
Student.prototype = new Person();
// Add Student methods
Student.prototype.setId = function(id) {
this.id = id;
}
Student.prototype.getId = function() {
return this.id;
}
var p0 = new Student('Sally', '1234');
var p1 = new Person('James');
alert('p0\'s id is ' + p0.id + ' and name is: ' + p0.name);
alert('p1\'s name is: ' + p1.name);
alert('Is p0 a student? ' + (p0 instanceof Student));
alert('Is p1 a student? ' + (p1 instanceof Student));
Note that the instanceof operator is not very reliable, but it works fine in the above case. Also all methods and properties are public so easily over written.

Categories

Resources