I want to call the super method in an extended javascript 'class' by applying classical inheritance.
function Person(name, age) {
this._name = name;
this._age = age;
}
Person.prototype.exposeInfo = function() {
alert(this._name + ' - ' + this._age);
}
function Employee(name, age) {
this.parent.constructor.call(this, name, age);
}
Employee.prototype.exposeInfo = function() {
alert('Call employee');
this.parent.exposeInfo();
}
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.parent = Person.prototype;
var p1 = new Person('John Doe', 30);
p1.exposeInfo();
var p2 = new Employee('John Foobar (empl.)', 35);
p2.exposeInfo();
JS Fiddle
The problem is that the method is not being called in the extended class, but only in the parent (Person).
That's because the overriding exposeInfo is being attached to the former prototype object, which is then replaced:
Employee.prototype = Object.create(Person.prototype);
You'll want to reverse the order, attaching methods after creating the prototype:
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.parent = Person.prototype;
Employee.prototype.exposeInfo = function() {
// ...
}
You'll also need to use .call() or .apply() with exposeInfo as you did with the constructor:
Employee.prototype.exposeInfo = function() {
alert('Call employee');
this.parent.exposeInfo.apply(this, arguments);
}
Otherwise, the value of this will be determined by the last member operator:
// so, calling:
this.parent.exposeInfo();
// is equivalent to:
alert(this.parent._name + ' - ' + this.parent._age);
// ...
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.parent = Person.prototype;
Employee.prototype.exposeInfo = function() {
this.parent.exposeInfo.apply(this, arguments);
// ...
}
It's not going to work.
Example:
// ...
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.parent = Person.prototype;
Employee.prototype.exposeInfo = function() {
this.parent.exposeInfo.apply(this, arguments);
// ...
}
ParttimeEmployee = Object.create(Employee.prototype);
ParttimeEmployee.prototype.constructor = ParttimeEmployee;
ParttimeEmployee.prototype.parent = Employee.prototype;
ParttimeEmployee.prototype.exposeInfo = function() {
this.parent.exposeInfo.apply(this, arguments);
// ...
}
var p1 = new Person('Jack', 30);
p1.exposeInfo(); // ok
var p2 = new Employee('Jane', 25);
p2.exposeInfo(); // ok
var p3 = new ParttimeEmployee('John', 20);
p3.exposeInfo(); // infinite recursion !!!
Correct version:
// Person
function Person(name, age) {
this._name = name;
this._age = age;
}
Person.prototype.exposeInfo = function() {
alert(this._name + ' - ' + this._age);
}
// Employee
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.parent = Person.prototype; // <--
Employee.prototype.exposeInfo = function() {
Employee.parent.exposeInfo.apply(this, arguments); // <--
// ...
}
// ParttimeEmployee
ParttimeEmployee = Object.create(Employee.prototype);
ParttimeEmployee.prototype.constructor = ParttimeEmployee;
ParttimeEmployee.parent = Employee.prototype; // <--
ParttimeEmployee.prototype.exposeInfo = function() {
ParttimeEmployee.parent.exposeInfo.apply(this, arguments); // <--
// ...
}
var p1 = new Person('Jack', 30);
p1.exposeInfo(); // ok
var p2 = new Employee('Jane', 25);
p2.exposeInfo(); // ok
var p3 = new ParttimeEmployee('John', 20);
p3.exposeInfo(); // ok
Related
What would be the difference between the following two ways of attaching a method(?) to a parent function:
var Person = function(first, last) {
this.first = first;
this.last = last;
};
Person.prototype.personMethod = function() {
// ...
};
And:
var Person = function(first, last) {
this.first = first;
this.last = last;
this.personMethod = function() {
// ...
};
}
In the first approach, the method is put onto the prototype. Every instance will share the same personMethod because every instance inherits from Person.prototype.
var Person = function(first, last) {
this.first = first;
this.last = last;
};
Person.prototype.personMethod = function() {
// ...
};
const p1 = new Person();
const p2 = new Person();
console.log(p1.personMethod === p2.personMethod);
console.log(p1.hasOwnProperty('personMethod'));
console.log(Object.getPrototypeOf(p1).hasOwnProperty('personMethod'));
console.log(Object.getPrototypeOf(p1) === Person.prototype);
In the second approach, every instance has its own separate method, and it's not on the prototype.
var Person = function(first, last) {
this.first = first;
this.last = last;
this.personMethod = function() {
// ...
};
}
const p1 = new Person();
const p2 = new Person();
console.log(p1.personMethod === p2.personMethod);
console.log(p1.hasOwnProperty('personMethod'));
In modern JavaScript, it's usually preferable to use a class instead, which puts methods onto the prototype.
class Person {
constructor(first, last) {
this.first = first;
this.last = last;
}
personMethod(){}
};
const p1 = new Person();
const p2 = new Person();
console.log(p1.personMethod === p2.personMethod);
console.log(p1.hasOwnProperty('personMethod'));
console.log(Object.getPrototypeOf(p1).hasOwnProperty('personMethod'));
console.log(Object.getPrototypeOf(p1) === Person.prototype);
Assigning the function inside the constructor can be useful if you want the function to close over a variable only scoped to the constructor, which wouldn't work for methods if the variable isn't set to the instance.
var Person = function(first, last) {
// say we don't want to assign these arguments to the instance
// but we can still do
this.getName = () => first + ' ' + last;
}
const p = new Person('John', 'Doe');
console.log(p.getName());
How can the retirementAge method access the value of calculateAge method in the same Person function constructor?
var Person = function(name, job, yearOfBirth) {
this.name = name;
this.yearOfBirth = yearOfBirth;
this.calculateAge = function() {
console.log(2018 - this.yearOfBirth)
};
this.retirementAge = function(el) {
console.log(66 - this.calculateAge)
}
}
var john = new Person('John', 'teacher', 1998);
john.retirementAge(john.calculateAge());
You need to return a value from this.calculateAge if you want to get the value by calling it. When you do that, you can just call the function this.calculateAge() and it should work as expected:
let Person = function(name, job, yearOfBirth) {
this.name = name;
this.yearOfBirth = yearOfBirth;
this.calculateAge = function() {
return 2018 - this.yearOfBirth
};
this.retirementAge = function(el) {
return 66 - this.calculateAge()
}
}
var john = new Person('John', 'teacher', 1998);
console.log("Age:", john.calculateAge())
console.log("Years to retirement:", john.retirementAge())
It can access it, you just forgot the parentheses and return the value.
var Person = function(name, job, yearOfBirth) {
this.name = name
this.yearOfBirth = yearOfBirth
this.calculateAge = function() {
return 2018 - this.yearOfBirth
};
this.retirementAge = function(el) {
return 66 - this.calculateAge()
}
}
var john = new Person('John', 'teacher', 1998);
console.log(john.retirementAge(john.calculateAge()))
I'm learning JavaScript and write a simple demo, but failed. Could you help me out why getName is not a function? Thanks.
var newPerson = function(name) {
this.name = name;
getName: return function() {
return this.name;
}
};
var personOne = newPerson("Diego");
var personTwo = newPerson("Gangelo");
console.log(personOne.getName()); // prints Diego
console.log(personTwo.getName()); // prints Gangelo
It looks like you're trying to return an object with some exposed methods. In that case, this is what I would have done.
var newPerson = function (name) {
this.name = name;
var self = this;
return {
getName: function () {
return self.name
}
}
}
var personOne = new newPerson("Diego");
var personTwo = new newPerson("Gangelo");
console.log(personOne.getName()); // prints Diego
console.log(personTwo.getName()); // prints Gangelo
Edit: thanks to Pootie
Alternatively you could just do this.
var newPerson = function (name) {
this.name = name;
this.getName = function () {
return this.name;
}
}
var personOne = new newPerson("Diego");
var personTwo = new newPerson("Gangelo");
console.log(personOne.getName()); // prints Diego
console.log(personTwo.getName()); // prints Gangelo
Next time, use console.log() instead of document.write() because it's easier to debug.
I would have done it like this
var Person = function(name) {
this.name = name;
this.getName = function() {
return this.name;
}
};
var personOne = new Person("Diego");
var personTwo = new Person("Gangelo");
document.write(personOne.getName()); // prints Diego
document.write(personTwo.getName()); // prints Gangelo
Since you said you liked my example I thought I'd post my personal preference. No need to return an object like the other examples do since the function itself is an object. Everything in JS is an object as a matter of fact.
See this fork of the other answer: https://jsfiddle.net/6xpgjh94/
var newPerson = function (name) {
var self = this;
self.name = name;
self.getName = function(){
return self.name
};
}
var personOne = new newPerson("Diego");
var personTwo = new newPerson("Gangelo");
console.log(personOne.getName()); // prints Diego
console.log(personTwo.getName()); // prints Gangelo
Well if we're introducing Object-Oriented Programming, I might as well show you how JavaScript does it best:
// The ECMAScript 5 way
function Person(name) {
this.name = name;
}
Person.prototype.getName = function getName() {
return this.name;
};
var personOne = new Person("Diego");
var personTwo = new Person("Gangelo");
console.log(personOne.getName());
console.log(personTwo.getName());
This next one uses ES6 Classes and is part of the new JavaScript standard.
Note this syntax is still in the "experimental stage" as far as browser implementation goes, and may not work on your browser.
// The ECMAScript 6 way
class Person {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
let personOne = new Person("Diego");
let personTwo = new Person("Gangelo");
console.log(personOne.getName());
console.log(personTwo.getName());
I have tried to create an instance of object internally like the following:
var oo = function(){
return new func();
}
var func = function(){
this.name;
this.age;
};
func.prototype = {
setData: function(name, age){
this.name = name;
this.age = age;
},
getData: function (){
return this.name + " " + this.age;
}
}
When usage, I got an error oo.setData is not a function.
oo.setData("jack", 15);
console.log(oo.getData());
What's wrong in my code?
This happens because oo is not a "func", oo returns a new func. You could set the data using
oo().setData('jack',15);
But then you have no way of accessing it.
You could also use
var newfunc = oo();
newfunc.setData('jack',15);
newfunc.getData();
oo is a function to create a object.
var oo = function(){ //the oo variable is used to create func() objects
return new func();
}
var func = function(){ //function
this.name;
this.age;
};
func.prototype = { //define properties to func
setData: function(name, age){
this.name = name;
this.age = age;
},
getData: function (){
return this.name + " " + this.age;
}
}
//create instance
var myObject = oo();
//or
var myObject = new func();
//Use
myObject.setData("jack", 12);
//Get a property
console.log(myObject.getData())
// 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() {
this.name = "penguin";
this.numLegs = 2;
}
// set its prototype to be a new instance of Animal
var penguin = new Animal("Penguin", 2);
penguin.sayName();
The compiler asks me to "Create a new Penguin instance called penguin"...
not sure what I'm doing wrong here
Here's how to make a Penguin object that inherits from Animal using prototypal inheritance in javascript:
// 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() {
this.name = "penguin";
this.numLegs = 2;
}
// set its prototype to be a new instance of Animal
Penguin.prototype = new Animal();
// Create new Penguin
var penguin = new Penguin();
penguin.sayName(); // outputs "Hi my name is penguin"
var legCount = penguin.numLegs; // outputs 2
Here's an article that explains JavaScript Prototypal Inheritance in detail:
http://pietschsoft.com/post/2008/09/JavaScript-Prototypal-Inheritence-Explained-in-Simple-Terms