create subclass object with reference to existing object - javascript

In node.js (Javascript) I have two classes, class mainclass and subclass, where subclass inherites from mainclass.
In an other module (other class, other .js file) i have an array of objects from class mainclass:
myArray[0] = new mainclass();
myArray[1] = new mainclass();
//etc..
On runtime, i want to create a new subclass object, and set its reference to the one in myArray[0], so that myArrayis not changed, but myArray[0] then returns the new subclass object.
And i want to do this in the mainclass, so that the array is not changed, but the reference in the array points now to an other object (the new subclass object). In fact i want to do something like
this = new subclass();
in a method in mainClass
mainClass.prototype.changeType = function(){
this = new subclass();
}
which of course doesnt work because you cant assign value to this.

You could "simulate" pointers if you are ready to access your objects through indexes. As you can see below, whatever object reference is at index 0, it remains available :
function Person (name) { this.name = name; };
Person.prototype.whoami = function () { return this.name };
memory = [];
memory.push(new Person("Hillary Clinton"));
memory[0].whoami(); // "Hillary Clinton"
memory[0] = new Person("Donald Trump");
memory[0].whoami(); // "Donald Trump"
Good luck though... x-D

Related

Javascript inheritence .Why does my class share nested member data?

I am having difficulty with the following inheritance code that I read in Crockfords book.
When I create two instances of a Column object the "this.name" member data is different in each instance, as I would have expected.
However, when I use nested member data "this.model.name" it is always shared among the instances.
Can anyone suggest a way to fix this?
var BaseColumn = function() {
this.model = {};
this.model.name = "";
this.name="";
};
var Column = function (name) {
this.model.name = name;
this.name = name;
};
Column.prototype = new BaseColumn();
var col1 = new Column("Column1");
var col2 = new Column("Column2");
alert(col1.name); //Returns "Column1"
alert(col2.name); //Returns "Column2"
alert(col1.model.name); //Returns "Column2"
alert(col2.model.name); //Returns "Column2"
This is because every instance of Column will have a reference to the SAME model object in the prototype. Creating the second Column overwrites the previous value of model.name.
Let's look at your code more closely to see why you are getting what you are:
var BaseColumn = function() {
this.model = {};
this.model.name = "";
this.name="";
};
This creates a type BaseColumn constructor that will create properties model and name on the new object when invoked using new.
var Column = function (name) {
this.model.name = name;
this.name = name;
};
This creates a type Column constructor that will fail. If you called new Column() now, it would fail on this.model (at this moment).
Column.prototype = new BaseColumn();
This REPLACES the existing prototype with a NEW prototype created from a new instance of BaseColumn. This object contains the properties I mentioned above for this type, and the property values will be SHARED across ALL Column objects. Why? Because if the local Column instance (col1 or col2) doesn't contain a property, the prototype chain is searched for one. Since all Column instances shared the same prototype, they all end up referencing the same values.
var col1 = new Column("Column1");
Did you know that at this point, Column.prototype.model.name == "Column1"?
var col2 = new Column("Column2");
Column.prototype.model.name is now "Column2"`. You see, the prototype is NOT duplicated. It is SHARED.
If the desire is to have one model per instance, you will have to construct a new model object for each new Column.
For a better way to approach inheritance, take a look at the answer by Juan Mendes. In this pattern, you are calling the base constructor explicitly from the constructor of your sub type. This will add/construct the base properties, and should be placed at the top of the sub type's constructor (usually).
The answer provided by James Wilkins is correct. There is only one instance of BaseColumn being created and it's shared by all instances of Columns through Column.prototype
However, it's worth noting that your way of establishing inheritance is incorrect. There's no need to instantiate a parent just to set up inheritance, and you need to call the parent's constructor from your constructor.
See my posts at http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html and http://js-bits.blogspot.com/2014/10/understanding-prototypical-inheritance.html for further details
The following example works fine.
var BaseColumn = function() {
this.model = {};
this.model.name = "";
this.name = "";
};
var Column = function(name) {
// Call the parent's constructor, a new model object will be created
// instead of using a shared one from the prototype
BaseColumn.apply(this);
this.model.name = name;
this.name = name;
};
Column.prototype = Object.create(BaseColumn.prototype);
var col1 = new Column("Column1");
var col2 = new Column("Column2");
console.log(col1.name); //Returns "Column1"
console.log(col2.name); //Returns "Column2"
console.log(col1.model.name); //Returns "Column1"
console.log(col2.model.name); //Returns "Column2"
This is because the value of model is inherited from BaseColumn for all instances of Column. You need to explicitly assign a value to the model property to make it unique. The way to can tell is by evaluating col.__proto__.model and see that model is indeed part of the prototype.
The answer is very simple: the {} is parsed once by JS and refers to the identical object in each instance you create. To create a new, different object for each instance, just do something like
this.model = Object.create();
or
this.model = new Object();
or
this.model = function() { return {}; }();
However, there are other issues with how you've got inheritance set up, that the other answers may help you with.

Value of constructor and prototype gets changed after over writing the prototype object. Why?

I have the Director() function. I have created 2 instances AlfredH and JohnD out of Director() constructor. I did not write the prototype object.
function Director(){
this.genre = "Thriller";
}
var AlfredH = new Director();
var JohnD = new Director();
If I check the values of JohnD.constructor; and JohnD.constructor.prototype; I get Director() and Object() respectively.
But, if I add properties to prototype object of Director() like the below:
function Director(){
this.genre = "Thriller";
}
Director.prototype = {
noir: true
};
var AlfredH = new Director();
var JohnD = new Director();
and if I check the values of JohnD.constructor; and JohnD.constructor.prototype; I get Object() and Object() respectively. Can anyone explain this behavior? and the same can be extended to the value of JohnD.constructor.prototype.constructor;
var a = {
value:22;
}
then
var a = {
somethingelse:0
}
Can you guess what a.value is?
You are overwriting the prototype with another object.
Then add to that that
console.log({}.constructor)===Object;//=true
Maybe try adding it like this:
Director.prototype.noir = true;
Note that anything on the prototype is shared among instances, this is a good thing because it saves memory and instantiate the object quicker with less cpu.
When assigning a new value the value is assigned to the instance but when manipulating the value through functions it affects all instances
Director.prototype.someArray=[];
var d1=new Director();
var d2=new Director();
d1.someArray.push(22);
console.log(d2.someArray);//=[22]
More info on prototype here: https://stackoverflow.com/a/16063711/1641941

use of prototype in javascript

I am learning prototype in JavaScript and this is the code I am trying -
<script>
function employee(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
var trialcoder = new employee('trialcoder', 26, 'M');
//employee.prototype.salary = null;
trialcoder.salary = 19000;
document.write("salary is "+ trialcoder.salary);
</script>
My thoughts- To add another property we need to use prototype like - employee.prototype.salary = null; so on un commenting this line, I was expecting an error but it was not..let me know where I am wrong in the prototype concept.
Code Source - http://www.w3schools.com/jsref/jsref_prototype_math.asp
Your code is correct, because when you called
var trialcoder = new employee('trialcoder', 26, 'M');
You got an object instance of employee and just like any other object you can add properties to your trialcoder object like
trialcoder.salary = 19000;
In this case, the salary property is only available to your trialcoder object and if you make another instance of employee like var another = new employee() you have no salary property in another object, but, if you do something like
function employee(name, age, sex) { //... }
employee.prototype.salary = 19000;
and then make instances like
var anEmp = new employee();
console.log(anEmp.salary); // 19000
Make another instance
var newEmp = new employee();
console.log(newEmp.salary); // 19000
if you want, you can
newEmp.salary = 10000;
console.log(anEmp.salary); // 10000
Which means, when you add a property in the prototype of a constructor (employee) then every object instance can share the same property and after making an instance from the constructor, you can change the property of an instance but this won't effect other instances. Hope it's clear enough now.
Your code is right and you will not receive error because using prototype your setting property salary of class employee and after creating an object of your class ur are setting the property for that specific object,if you create another object you can set its property salary too
If you set property using prototype then all objects of that class will share that (salary) property .

JavaScript creating new instance of objects

So I am designing a grade book interface and I have a course defined as:
<script>
course = new Object();
var name;
var gradingareas;
var finalgrade;
</script>
then later I want to create a new instance:
var gradingareas = new Array("Homework", "Classwork", "Exams");
course1 = new course("CS1500", gradingareas, 85);
I have also tried without the var in front to no avail. I get an "Uncaught TypeError: Object is not a function" I am very new to javascript so I don't even know if Im going about this the correct way. Any help is appreciated Thanks.
Your existing code:
// Creates a new, empty object, as a global
course = new Object();
// Creates three new variables in the global scope.
var name;
var gradingareas;
var finalgrade;
There is no connection between the variables and the object.
It looks like you want something more like:
function Course(name, gradingareas, finalgrade) {
this.name = name;
this.gradingareas = gradingareas;
this.finalgrade = finalgrade;
}
Then:
var course1 = new Course("CS1500", gradingareas, 85);
Note the use of a capital letter for naming the constructor function. This is a convention in the JS community.
JS is prototypical, rather than class based and if you are new to it there are advantages to learning this immediately rather than trying to mush classical inheritance models from it, however, classical inheritance is alive and well in JS.
Anyhow, to answer how you would access your variables:
course1.name works fine with the example above.
If you wanted to privatise your data you could take this approach using closure:
var Course = function(name, grade) {
// Private data
var private = {
name: name,
grade: grade
}
// Expose public API
return {
get: function( prop ) {
if ( private.hasOwnProperty( prop ) ) {
return private[ prop ];
}
}
}
};
Then instantiate a new object:
var course = new Course('Programming with JavaScript', 'A');
and start using all that private data:
course.get('name');
Of course, you'd probably want setters to manipulate that data too ;)
The code that you described does the following:
// Declares a memory variable called course and stores and object in it
var course = new Object();
// Declares three variables
var name;
var gradingareas;
var finalgrade;
These declared variables aren't automatically connected to the object. If you want these properties declared on the object you have 2 options:
Declare them as properties of the object
Declare them on the prototype of of the object
Example1: declare them as properties of the object:
// Declares a memory variable called course and stores and object in it
var course = new Object();
// Access or create new properties with . or [] operator
course.name = 'math';
course.gradingareas = 'muliple';
course['finalgrade'] = 'A'
console.log(course);
Example2: Declare them on the prototype:
// Create a constructor function
function Course (name, grade) {
this.name = name;
this.grade = grade;
}
// course is added on the prototype
Course.prototype.gradingareas = 'some gradingareas';
// the name and the grade are added on the object itself
var course = new Course ('willem', 10);
console.log(course);
To create a very simple object with constructor and default values, you can do :
//My object with constructor
var myObjectWithConstrutorFunction = {
//construtor function with default values in constructor
myConstrutor: function(Name = 'bob', Age = 18){
this.Name = name;
this.Age = age;
}
};
// instance
var myInstance = new myObjectWithConstrutorFunction.myConstrutor();
// show on console
console.log('object with constructor function: ', myInstance);
// show properties
console.log(myInstace.Name, myInstance.Age);
PS : It's a good practice create a constructor's name with the same name of the class, if you are creating a external class.

JavaScript property inheritance

I'm trying to have a generic 'List' class, which will have:
Property: Items - which would be an array of 'what-ever'
Method: Add() - which would be abstract and implemented by the specific 'List' object
Method: Count() - which returns the number of 'items'
And then create sub-classes which will inherit from 'List':
// Class 'List'
function List(){
this.Items = new Array();
this.Add = function(){ alert('please implement in object') }
}
// Class CDList - which inherits from 'List'
function CDList(){
this.Add = function(Artist){
this.Items.push(Artist)
}
}
CDList.prototype = new List();
CDList.prototype.constructor = CDList;
// Create a new CDList object
var myDiscs = new CDList();
myDiscs.Add('Jackson');
myDiscs.Count() <-- this should be 1
// Create a second CDList object
var myDiscs2 = new CDList();
myDiscs2.Add('Walt');
myDiscs2.Add('Disney');
myDiscs2.Count() <-- this should be 2
...but this seems to create a shared 'Items' list for all 'CDList' instances. I need to somehow have a new inherited instance of the 'Items' list for each 'CDList' instance.
How can I do this?
*I'm using in this example the 'Items' list as an example. I'd like to be able to have in my sub-classes a new instance for any type of inherited property - not necessarily an Array object.
There is only one Array because you only create one. This array is attached to the prototype of "CDList" and therefore shared between all instances.
To solve this problem: don't attach it to the prototype, but to the instance. This can only be done at construction time:
// This is the constructor of the parent class!
function List() {
this.Items = new Array();
}
// Add methods to the prototype, not to the instance ("this")
List.prototype.Add = function() { alert('please implement in object'); };
// Constructor of the child
function CDList() {
List.call(this); // <-- "super();" equivalent = call the parent constructor
}
// "extends" equivalent = Set up the prototype chain
// Create a new, temporary function that has no other purpose than to create a
// new object which can be used as the prototype for "CDList". You don't want to
// call "new List();", because List is the constructor and should be called on
// construction time only. Linking the prototypes directly does not work either,
// since this would mean that overwriting a method in a child overwrites the
// method in the parents prototype = in all child classes.
var ctor = function() {};
ctor.prototype = List.prototype;
CDList.prototype = new ctor();
CDList.prototype.constructor = CDList;
// Overwrite actions
CDList.prototype.Add = function(Artist) {
this.Items.push(Artist);
};
Demo: http://jsfiddle.net/9xY2Y/1/
The general concept is: Stuff that each instance must have its own copy of (like the "Items" array in this case) must be created and attached to "this" (= the instance) at construction time, i.e. when doing new List() or new CDList(). Everything that can be shared across instances can be attached to the prototype. This essentially means that properties like the "Add" function are created exactly one time and are then used by all instances (what caused the original issue).
When linking prototypes, you must not directly link them (usually), e.g.:
CDList.prototype = List.prototype;
DVDList.prototype = List.prototype;
// Now add a new function to "CDList"
CDList.prototype.Foo = function() { alert('Hi'); };
Because the prototypes of the three functions "List", "CDList" and "DVDList" got directly linked to each other, they all point to one prototype object, and that is List.prototype. So, if you add something to CDList.prototype you actually add it to List.prototype - which also is the prototype of "DVDList".
var dvd = new DVDList();
dvd.Foo(); // <-- alerts "hi" (oops, that wasn't intended...)
What does the trick is to link the prototype to a new instance of the parent class:
CDList.prototype = new List();
This creates a new object of type "List()" with the special feature that the prototype of the function "List()" is linked to the new object, enabling you to call properties of the prototype directly on the object:
var l = new List();
alert( l.hasOwnProperty("Add") ); // <-- yields "false" - the object l has no
// property "Add"
l.Add("foo"); // <-- works, because the prototype of "List" has a property "Add"
However, remember that we intended to use the body of the function "List()" to create stuff like this array "Items" on a per-instance basis? It is the place where you put any "constructor" code, e.g.
function User(userId) {
$.getJSON('/user/' + userId, ...
}
function Admin() {}
Admin.prototype = new User( // ... now what?
One very clean solution is to use another function to create a prototype-object:
var ctor = function() {}; // <-- does nothing, so its super safe
// to do "new ctor();"
It is now okay to directly link the prototypes, because we will never add anything to ctor.prototype:
ctor.prototype = List.prototype;
If we then do:
CDList.prototype = new ctor();
the prototype of "CDList()" becomes a new object of type "ctor", that has no own properties but can be extended, e.g. by a new "Add" function:
CDList.prototype.Add = function() { /* CD specific code! */ };
However, if you do not add an "Add" property to this new prototype object, the prototype of "ctor()" kicks in - which is the prototype of "List()". And that's the desired behavior.
Also, the code in "List()" is now only executed whenever you do new List() or when you call it directly from another function (in a child class via List.call(this);).
Try this:
function CDList(){
List.call( this )
this.Add = function(Artist){
this.Items.push(Artist)
}
}
You need to call the superconstructor...
I like this article of the MDN network about JavaScript inheritance. I tried this method/technique and it works very fine in all browsers I tested (Chrome, Safari, Internet Explorer 8+, and Firefox)..

Categories

Resources