I am having some Problems with JavaScript. I have got the following code:
<html>
<head>
<title>Test</title>
<script type="text/javascript">
function Control(){
var name;
this.setName = function(newName){
name = newName;
};
this.getName = function(){
return name;
};
}
function SpecializedControl(){
}
SpecializedControl.prototype = new Control();
function Form(){
var formControls = [];
this.addControl = function(control){
formControls.push(control);
alert(formControls[0].getName());
};
}
var form = new Form();
var control1 = new SpecializedControl();
control1.setName("Control1");
form.addControl(control1);
var control2 = new SpecializedControl();
control2.setName("Control2");
form.addControl(control2);
</script>
</head>
<body>
</body>
</html>
The SpecializedControl inherits from the Control class.
The addControl function in the Form class just adds the control to an array.
The problem is that when I add more than one SpecializedControl, the values in the array are kind of overriden, that means that when I access the first item in the array, which should be "Control1" I get "Control2". Control1 is not in the array any longer.
When I use the same function with Control objects as parameters everything works as expected.
Does someone know why this happens and what can be done to correct this?
The values in the array aren't being overridden; the problem is both controls share the same name variable. Because the Control function only executes once, there is only one name variable ever declared.
You have two main options to fix this. (1) Make name an instance variable which is specific to each individual control (e.g. this._name). (2) Execute the Control function from inside the SpecializedControl constructor. (Actually, IMO, for a well-balanced and thorough inheritence model you should be doing a bit of both of these methods).
Here are three working solutions. The first two use options (1) and (2) respectively. The third combines both methods and is the way I would do it (but requires joi).
Option 1:
function Control(){
this.setName = function(newName){
this._name = newName;
};
this.getName = function(){
return this._name;
};
}
Option 2:
function SpecializedControl(){
Control.apply(this, arguments);
}
Option 3:
var Control = joi.Unit.sub(function() {
function constructor() {
this.base();
}
constructor.prototype = {
'#name': null,
setName: function(name) {
this['#name'] = name;
},
getName: function() {
return this['#name'];
}
};
return constructor;
}());
var SpecializedControl = Control.sub(function() {
function constructor() {
this.base();
}
return constructor;
}());
var Form = joi.Unit.sub(function() {
function constructor() {
this.base();
this['#formControls'] = [];
}
constructor.prototype = {
'#formControls': null,
addControl: function(control) {
this['#formControls'].push(control);
alert(this['#formControls'][0].getName());
}
};
return constructor;
}());
var form = new Form();
var control1 = new SpecializedControl();
control1.setName("Control1");
form.addControl(control1);
var control2 = new SpecializedControl();
control2.setName("Control2");
form.addControl(control2);
Your get/setName functions are getting/setting the value of the name variable that is local to the Control constructor function.
The only time you invoked that function, was to create an instance as the prototype object of SpecializedControl. So every time you invoked setName from a SpecializedControl instance, that single variable is being updated.
So since the get/setName methods that reference that variable are in the prototype chain of all SpecializedControl instances, they'll all be observing the same name.
In setName, you should do...
this.name = newName;
And in getName, you should do...
return this.name;
Related
Firstly, sorry for my lack of terminology.
If I have a constructor
function myObject(name, value){
this.name = name;
this.value = value;
}
and I make a few objects from it
var One = new myObject("One", 1);
var Two = new myObject("Two", 2);
Can I loop through each new Object made from the myObject class, without putting each new Object into an Array?
would it be possible to add an Instantly Invoking Function to the constructor that adds the Object into an array?
e.g.
function myObject(name, value){
this.name = name;
this.value = value;
this.addToArray = function(){
theArray.push(this); // this is the IIFE
}();
}
that way any new objects created instantly run this function and get added to the array.
Is this possible? ( current syntax does not work, obviously )
EDIT Coming back to this one year later I can tell you that it IS possible. You just call the function inside the constructor like so:
function myObject(name, value){
this.name = name;
this.value = value;
this.addToArray = function(){
theArray.push(this);
};
this.addToArray();
}
Here is an example of this in JSFIDDLE, pushing each object into an array on instantiation and then calling each object's .speak() method directly from the array.
https://jsfiddle.net/Panomosh/8bpmrso1/
Without using an array, you can't, it is not the way it is meant to be used.
What you can do though, is watch over each instances created in a static member of myObject class
function myObject(name, value){
this.name = name;
this.value = value;
this.watch();
}
myObject.prototype.watch = function () {
if (myObject.instances.indexOf(this) === -1) {
myObject.instances.push(this);
}
};
myObject.prototype.unwatch = function () {
myObject.instances.splice(myObject.instances.indexOf(this), 1);
};
myObject.instances = [];
No, you cannot. You cannot do this with almost all programming languages.
You can, in the constructor, store a reference of every object you created into an array/map so that you can iterate over them any time. This, however, prevents all objects of this class from being garbage collected, so use it with care.
The WeakMap in JavaScript keeps only a week reference to the keys, but it, in turn, does not allow you to loop over all keys. So it is not an option either.
var MyClass = (function() {
var _instances = [];
function MyClass(name, value) {
_instances.push(this);
this.name = name;
this.value = value;
}
MyClass.each = function(cb) {
for (var i in _instances) {
if (_instances.hasOwnProperty(i)) {
cb(_instances[i]);
}
}
}
return MyClass;
})();
new MyClass('John', 10);
new MyClass('James', 20);
MyClass.each(function(item) {
console.log(item);
});
I am a typical Java programmer with traditional OOPs knowledge. I am trying to learn JS now. I have learned that a function is JS is a first class object, like any other object it has properties and methods. based on this I have written following code:
function Note(name, text)
{
this.name = name;
this.text = text;
function displayNote()
{
alert(this.text);
}
}
I am now trying to access the displayNote function from the not object, with the follwing code:
var note = new Note("a", "c");
alert(note.displayNote);
But it alerts undefined. This may be due to the scope issue. So I tried with this:
function Note(name, text)
{
this.name = name;
this.text = text;
function displayNote()
{
var self = this;
alert(self.text);
}
}
var note = new Note("a", "c");
alert(note.displayNote);
Still the same result. Any explanations?
You need to do:
function Note(name, text)
{
this.name = name;
this.text = text;
this.displayNote = function()
{
alert(this.text);
}
}
It is showing undefined, because you haven't defined the displayNote property.
Also, to call a function you need to do:
var note = new Note("a", "c");
note.displayNote();// it will automatically alert. Otherwise you'll have two alerts. The second one being undefined.
Live Demo
Try this.
this.displayNote = function()
{
alert(this.text);
}
Now it's a property of the Note object. Plus I think you want to do this:
note.displayNote(); // Note the brackets to call.
In here with the code as
alert(note.displayNote);
You are calling the alert twice.
So please just call the function
note.displayNote();
you can use like below
<script language="javascript" type="text/javascript">
<!--
person = new Object()
person.name = "Tim Scarfe"
person.height = "6Ft"
person.run = function() {
this.state = "running"
this.speed = "4ms^-1"
}
//-->
</script>
http://jsfiddle.net/F5ZSA/1/
Here's the code from above fiddle:
"use strict";
function Human()
{
this.myname;
this.things = [];
this.addThing = function(string)
{
this.things.push(string);
}
this.getThings = function()
{
return this.things;
}
this.setName = function(name)
{
this.myname = name;
}
this.getName = function()
{
return this.myname;
}
}
Mister.prototype = new Human();
function Mister()
{
}
var mister1 = new Mister();
var mister2 = new Mister();
mister1.setName("Peter");
mister2.setName("Steven");
mister1.addThing("mister1 reporting");
mister2.addThing("mister 2 reporting");
console.log(mister1.getName());
console.log(mister2.getName());
console.log(mister1.getThings());
console.log(mister2.getThings());
When you run it, the result suggests that 'myname' property is different for each Mister instance, while 'things' property seems to be shared between all instances. Is it suppose to be like that? If yes, what is the general rule telling which prototype properties are shared among 'inheriting' objects?
Coming from other OOP languages, my intuition was that every object should have a separate prototype instance. Is it a good idea to try to enforce it in js?
This is the classic problem when coming from traditional OOP languages. By creating the new object the prototype is copied. The keyword 'this' already refers to new object, but the reference to another object from the prototype as yours this.things refers still to the same space in the memory. When you create two objects you create two references to the same object (in this case array)
the following will work as you would expect. To go around the 'this' issue i put there the init method called to initialise the object, in this case to create multiple array objects, each for new object Mister.
var Human = function()
{
this.myname;
this.things;
this.things;
return {
addThing:function(string)
{
this.things.push(string);
},
getThings:function()
{
return this.things;
},
setName: function(name)
{
this.myname = name;
},
getName: function()
{
return this.myname;
},
init: function(){
this.things = new Array();
}
}
}
var Mister = function(){}
Mister.prototype = new Human();
var mister1 = new Mister();
var mister2 = Object.create(Mister.prototype);
mister1.init();
mister2.init();
mister1.setName("Peter");
mister2.setName("Steven");
mister1.addThing("mister1 reporting");
mister2.addThing("mister 2 reporting");
console.log(mister1.getName());
console.log(mister2.getName());
console.log(mister1.getThings());
console.log(mister2.getThings());
Here is a simple example of what I want :
var ConstBuilder = function() {
var constructor = function() {} ;
constructor.prototype = {} ;
return constructor ;
} ;
ConstBuilder.prototype = {
add : function(name, value) {
this.prototype[name] = value ;
}
} ;
var A = new ConstBuilder() ;
A.add('test', function() {
console.log('test') ;
}) ;
var a = new A() ;
a.test() ;
This code will fail as A is not an instance of ConstBuilder (because A comes from a returned var constructor = function() {} and won't have the methods defined in its prototype (add).
But this would be useful to modify the super constructor's prototype to have things like :
ConstBuilder.prototype.remove = function(name) {
delete this.prototype[name] ;
} ;
A.remove('test') ;
a.test ; // undefined
Is there a way to have a function as an instance of another ? So this function may implicitely "inherit" all the methods defined in its constructor's prototype.
Or if you have other suggestions, I aim to build modulable constructors - as instances with prototypes are.
Please make sure you have understood the difference between the .prototype property and the internal inheritance-prototype.
The code will fail as A is not an instance of ConstBuilder. Is there a way to have a function as an instance of another?
A is, as every constructor needs to be, a Function. So if you just define your add and remove methods on the Function.prototype, it will work:
Function.prototype.add = function(name, value) {
this.prototype[name] = value;
};
Function.prototype.remove = function(name) {
delete this.prototype[name];
};
function A() {}
A.add('test', function(){console.log('test');});
var a = new A();
a.test(); // test
A.remove('test');
a.test; // undefined
There is no possibility however to let a function inherit from something else than Function.prototype - see Can a JavaScript object have a prototype chain, but also be a function?. If you don't want to modify the native Function.prototype object, you still can use the mixin pattern:
var Constr = (function() {
function add(name, value) {
this.prototype[name] = value;
}
function remove(name) {
delete this.prototype[name];
}
return function mixin(c) {
c.add = add;
c.remove = remove;
return c;
};
})();
var A = Constr(function() {…});
A.add("test", …);
var a = new A();
a.test(); // test
I aim to build modulable constructors
You could use the builder pattern, as you just have seem to tried.
function ConstBuilder() {
this.prototype = {};
};
ConstBuilder.prototype = {
add: function(name, value) {
this.prototype[name] = value;
},
remove: function(name) {
delete this.prototype[name];
},
getConstructor: function() {
var constructor = function() {};
constructor.prototype = this.prototype;
this.prototype.constructor = constructor;
return constructor;
}
};
var A = new ConstBuilder().add('test', function() {
console.log('test');
}).getConstructor();
var a = new A();
a.test(); // test
To remove functions later, you would need to save a reference to the builder.
I think that you are looking for an example of how to do JavaScript's "prototypical inheritance". When JavaScript looks for a property on an object, it first checks the object itself. Next it checks the prototype. However, since everything in JavaScript is an object and the prototype is an object
function Root(){}
Root.prototype.fromRoot = function() { console.log("I'm on Root's prototype."); };
function Child(){}
Child.prototype = new Root();
Child.prototype.fromChild = function() { console.log("I'm on Child's prototype."); };
var r = new Root();
var c = new Child();
r.fromRoot(); // works
c.fromRoot(); // works
c.fromChild(); // works
r.fromChild(); // fails
function a (x,y,construct)
{
if (!construct) return;
this.x=x;
this.y=y;
}
a.prototype.methoda=function ()
{
return x+y;
}
function b (x,y,d,e)
{
a.call (this,x,y,true) //--- this would inherit all own Objects and Properties of a and become own properties of b
this.d=d;
this.e=e;
}
b.prototype=new a (); //--- this would only inherit the prototype, construct becomes false and isnt worked through, which if not would result in adding propertiy x and y to prototype instead of directly to instance of b,
b.prototype.constructor=b;
var test=new b (1,2,3,4);
b.methoda ();
second way
function a (x,y)
{
if (arguments.callee.doNotConstruct) return;
this.x=x;
this.y=y;
}
a.prototype.methoda=function ()
{
return x+y;
}
function b (x,y,d,e)
{
a.call (this,x,y) //--- this would inherit all own Objects and Properties of a and become own properties of b
this.d=d;
this.e=e;
}
a.doNotConstruct=true;
b.prototype=new a (); //--- this would only inherit the prototype, construct becomes false and isnt worked through, which if not would result in adding propertiy x and y to prototype instead of directly to instance of b,
a.doNotConstruct=false;
b.prototype.constructor=b;
var test=new b (1,2,3,4);
b.methoda ();
put this in a function
function prototypeInheritance (inheritor,parent)
{
parent.doNotConstruct=true;
inheritor=new parent ();
inheritor.prototype.constructor=inheritor;
inheritor.parent=parent;
parent.doNotConstruct=false;
}
you can call the parent property with (arguments.callee.parent) in the inheritor constructor and you can check doNotConstruct with arguments.callee.doNotConstruct in the parent constructor
is this possible?
We sure know how to emulate private members in javascript:
var Class = (function() {
var _private;
Class = function() {
_private = {};
};
Class.prototype.set = function(name, value) {
_private[name] = value;
};
Class.prototype.get = function(name) {
return _private[name];
};
return Class;
})();
The side effect of this pattern is that when I create two instances:
var instanceOne = new Class();
var instanceTwo = new Class();
then the private property is shared between:
instanceOne.set('test', 'me');
instanceTwo.get('test');
Is there some work around for this problem?
Regards
The standard way to have "private" members in JavaScript is to use local variables within the constructor and have anything that needs to access them defined as closures over the context of the call to the constructor, like this:
function Class() {
var privateValue = 0;
this.getPrivateValue = function() {
return privateValue;
};
}
Class.prototype.doSomething = function() {
// This function doesn't have access to `privateValue`
// except through `getPrivateValue`, even though
// it's accessible as a member of the instance
};
This has been described by many, probably most famously Douglas Crockford.
Note that this has the repercussion that each instance of Class gets its own copy of the getPrivateValue function, because each is a closure over a different call to the constructor (which is why it works). (This doesn't mean all the code of the function is duplicated, however; at least some engines — Google's V8 engine, used in Chrome and elsewhere for instance — allow the same code to be shared by multiple function objects which have different associated contexts.)
(Side note: I haven't used the name private because it's a reserved word. In ES3, it was a "future reserved word;" in ES5, it's only one in strict mode; details.)
I've used a simple variable above rather than an object to avoid making things look more complex than they are. Here's the way the would apply to your example:
function Class() {
var privateData = {};
this.get = function(name) {
return privateData[name];
};
this.set = function(name, value) {
privateData[name] = value;
};
}
Or if you still want to also have class-wide private data shared across instances:
var Class = function() {
var dataSharedAmongstInstances;
function Class() {
var privateDataForEachInstance = {};
this.get = function(name) {
return privateDataForEachInstance[name];
};
this.set = function(name, value) {
privateDataForEachInstance[name] = value;
};
}
return Class;
})();