I defined my classes like that:
function Employee () {
this.name = "";
this.val = new Array();
}
function WorkerBee () {
this.beeQueen = "lola";
this.setVal = function(val) {
this.val.push(val);
};
}
WorkerBee.prototype = new Employee;
function SalesPerson () {
this.dept = "development";
}
SalesPerson.prototype = new WorkerBee;
function Engineer () {
this.dept = "R&D";
}
Engineer.prototype = new WorkerBee;
Problem: all the objects I create share the same val array:
var mark = new WorkerBee;
mark.name = "Mark";
mark.setVal('00000')
var louis = new SalesPerson;
louis.name = "Louis";
louis.setVal('11111')
var ricky = new SalesPerson;
ricky.name = "Ricky";
ricky.setVal('33333')
var john = new Engineer;
john.name = "John";
john.setVal('55555');
This:
html += "<br /><br />Name: " + mark.name;
html += "<br />Val: " + mark.val;
html += "<br /><br />Name: " + louis.name;
html += "<br />Val: " + louis.val;
html += "<br /><br />Name: " + ricky.name;
html += "<br />Val: " + ricky.val;
html += "<br /><br />Name: " + john.name;
html += "<br />Val: " + john.val;
displays:
Name: Mark
Val: 00000,11111,33333,55555
Name: Louis
Val: 00000,11111,33333,55555
Name: Ricky
Val: 00000,11111,33333,55555
Name: John
Val: 00000,11111,33333,55555
I read http://yehudakatz.com/2011/08/12/understanding-prototypes-in-javascript/ and http://javascriptweblog.wordpress.com/2010/06/07/understanding-javascript-prototypes/ but I'm still confused!
When I use a string instead of an array this works well (because the reference to the string is overwritten I suppose) but how to do it with array ?
So I can have:
Name: Mark Val: 00000
Name: Louis Val: 11111
Name: Ricky Val: 33333
Name: John Val: 55555
2 Answers 2
You need to apply the "parent" constructor in your "inheriting" constructor functions:
function WorkerBee () {
Employee.apply(this);
/*...*/
}
WorkerBee.prototype = new Employee();
Do the same for all your "inherited" constructor functions:
function SalesPerson () {
WorkerBee.apply(this);
/*...*/
}
SalesPerson.prototype = new WorkerBee();
function Engineer () {
WorkerBee.apply(this);
/*...*/
}
Engineer.prototype = new WorkerBee();
And like @austincheney pointed out, JavaScript has no "classes" - only functions (which are objects), constructors (which are functions) and objects.
JavaScript uses prototypal inheritance. This means that when you try to access a property (or function) of an object which doesn't exist, it will delegate to the prototype object.
Consider:
var isaacNewton = {
name: 'Isaac Newton'
};
function Scientist() {}
Scientist.prototype = isaacNewton;
var neilDeGrasseTyson = new Scientist();
console.log(neilDeGrasseTyson.name);
isaacNewton.name = 'Sir Isaac Newton';
console.log(neilDeGrasseTyson.name);
The output here is:
Isaac Newton
Sir Isaac Newton
Object neilDeGrasseTyson hasn't inherited the name property. It simply doesn't have one. Since it doesn't have a property name when we try to access name the neilDeGrasseTyson object will delegate to the prototype object Scientist.prototype, and return the value of Scientist.prototype.name which is isaacNewton.name.
In your code, objects mark, louis, ricky and john don't have a property val. All those calls to setVal end up manipulating WorkerBee.prototype.val since none of those objects have their own val property. By applying the Employee constructor to them, you introduce the properties of an Employee to them, so they don't have to delegate.
To drive the point home a little more, another solution would have been to put the method setVal in Employee and give each "inheriting" constructor a this.val property: http://jsfiddle.net/FDCXF/1/
4 Comments
setVal function on Employee.prototype since it seems that everything inheriting from Employee will have its own val Array. Might as well share the function.val property is requested from an object created from Engineer, it first checks to see if it has that property. If not, it looks at its prototype, which is a WorkerBee object. If the WorkerBee object doesn't have it, it looks to its prototype, which is an Employee object. Because the Employee object has that property, that's the value that will be used. As a result, all objects inheriting from that original new Employee will all share the same Array.1) JavaScript does not have classes.
2) JavaScript only has function scope and not block scope.
3) A variable is only provided scope with the "var" keyword.
Re-engineer your code knowing this and see if you still encounter this problem.