1

What are the details why pe.getName() is working and pe.getSalary() is not?

var Employee = function(name) {
  this.name = name;
}

Employee.prototype.getName = function() {
  return this.name;
}

var PermanentEmployee = function(annualSalary) {
  this.annualSalary = annualSalary;
}

PermanentEmployee.prototype.getSalary = function() {
  return this.annualSalary;
}

var employee = new Employee("Mark");

PermanentEmployee.prototype = employee;

var pe = new PermanentEmployee(5000);

document.write(pe.getName());
document.write(pe.getSalary());
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
AhMed RaXa
  • 39
  • 7

2 Answers2

2

By doing this later in your code

PermanentEmployee.prototype = employee;

you might override this

PermanentEmployee.prototype.getSalary = function()

Try this instead:

function Employee(name) {
  this.name = name;
}

Employee.prototype.getName = function() {
  return this.name;
}
   
function PermanentEmployee(name, annualSalary) {
  Employee.call(this, name);  // calling parent's "constructor"
  this.annualSalary = annualSalary;
}
PermanentEmployee.prototype = Object.create(Employee.prototype); // setting "inheritance"
PermanentEmployee.prototype.getSalary = function() {
  return this.annualSalary;
}
var pe = new PermanentEmployee("Mark", 5000);

console.log(pe.getName());
console.log(pe.getSalary());
curveball
  • 4,320
  • 15
  • 39
  • 49
  • but what is actually happening behind the scenes of my code.. Please explain. – AhMed RaXa Apr 30 '17 at 13:44
  • 1
    you reset _ _proto_ _ ref. of `PermanentEmployee` object to `employee` object and function `getSalary()` that was there (in an object accessible through _ _proto_ _ ref. of `PermanentEmployee` object) before just became unaccessible. Since `getSalary()` is no longer accessible within `PermanentEmployee` object, JS tries to find it in a chain of prototypes and goes to `employee` object that doesn't have such a method nor have reference to an object with `getSalary()` method itself through its _ _proto_ _ and finally an error is thrown because `getSalary()` method isn't found anywhere. – curveball Apr 30 '17 at 13:59
  • This is quite essential, core part of Javascript and you would like to get it right from the start. I tried my best with the explanation above which is pretty accurate to my taste, but it may sound confusing to newbies, so, you should find additional material that cover this topic in more detail. That is my advice. – curveball Apr 30 '17 at 14:05
  • Well thank u sir it helped me a bit... i think i have to learn more about prototype and inhertance – AhMed RaXa Apr 30 '17 at 14:09
  • So of i declare `getSalary()` method inside the constructor function will it work then.? – AhMed RaXa Apr 30 '17 at 14:20
  • in your code you could put it like this: `Employee.prototype.getSalary = function()` taking this method from PermanentEmployee and adding it to Employee and it will work. – curveball Apr 30 '17 at 14:28
  • Also you should learn OOP in order to meaningfully use classes. So, it is quite unlikely to write good, working, maintainable, stable JS code without having solid notions of OOP and JS inheritance model. – curveball Apr 30 '17 at 14:34
0

This is actually the expected behavior. If you want to understand why, here we go...

Consider the following schema, available in the excellent book Exploring ES6 by Dr. Axel Rauschmayer.

enter image description here

Before to go on, here is an important rule: in JavaScript, when you create an instance of a "class", this instance will reference the prototype property of its constructor through its dunder proto (__proto__ or [[Prototype]]).

Top left

In your example, Employee and PermanentEmployee are constructor functions. Like any function in JavaScript, they are instances of Function and they use Function.prototype.

var Employee = function(name) {
  this.name = name;
}

var PermanentEmployee = function(annualSalary) {
  this.annualSalary = annualSalary;
}

console.log(typeof Object.getPrototypeOf(Employee)); // ES5
console.log(typeof PermanentEmployee.__proto__); // ES6

console.log(Object.getPrototypeOf(Employee).constructor); // ES5
console.log(PermanentEmployee.__proto__.constructor); // ES6

Top right

When you write Employee.prototype.getName or PermanentEmployee.prototype.getSalary, you are actually adding new properties to the prototype property of Employee and PermanentEmployee. But Employee.prototype and PermanentEmployee.prototype are instances of Object and use Object.prototype.

var Employee = function(name) {
  this.name = name;
}

Employee.prototype.getName = function() {
  return this.name;
}

var PermanentEmployee = function(annualSalary) {
  this.annualSalary = annualSalary;
}

PermanentEmployee.prototype.getSalary = function() {
  return this.annualSalary;
}

console.log(typeof Employee.prototype);
console.log(typeof PermanentEmployee.prototype);

console.log(Employee.prototype);
console.log(PermanentEmployee.prototype);

Since PermanentEmployee.prototype is a simple object, this is not reasonable to do so: PermanentEmployee.prototype = employee.

When you do that, you override the prototype. To make a basic comparison, look at this example with an object literal:

var obj = {
  foo: 'Foo'
};

obj.bar = 'Bar';

console.log(obj);

obj = 'Baz';

console.log(obj);

obj = {
  foo: 'Foo',
  bar: 'Bar',
  baz: 'Baz'
};

console.log(obj);

You should keep this in mind when you play with prototypes...

Bottom right

In JavaScript, there are several strategies to create a "pure" object (functions and arrays are objects too...). You can:

  • Use an object literal: {}
  • Use a constructor: new Object()
  • Use Object.create()

In your example, you are using constructors. Therefore, your instances will use the prototype properties of your constructors, which themselves use the prototype property of Object. This is how the prototype chain works!

var Employee = function(name) {
  this.name = name;
}

Employee.prototype.getName = function() {
  return this.name;
}

var PermanentEmployee = function(annualSalary) {
  this.annualSalary = annualSalary;
}

PermanentEmployee.prototype.getSalary = function() {
  return this.annualSalary;
}

var employee = new Employee("Mark");

console.log(Object.getPrototypeOf(employee)); // ES5
console.log(employee.__proto__.constructor); // ES6
console.log(Object.getPrototypeOf(Object.getPrototypeOf(employee))); // ES5
console.log(employee.__proto__.__proto__.constructor); // ES6

But of course, if you have completely overriden your prototype somewhere, you break the prototype chain and it will not work as expected...

Community
  • 1
  • 1
Badacadabra
  • 8,043
  • 7
  • 28
  • 49