Property shared between classes in javascript - javascript

function myclass(){
}
myclass.prototype = {
stuff: {},
getStuff: function(){
return Object.keys(this.stuff).length;
}
};
var m1 = new myclass();
m1.stuff[5] = 'test';
m1.stuff[6] = 'test';
var m2 = new myclass();
m2.stuff[12] = 'test';
m2.stuff[14] = 'test';
alert(m2.getStuff()); // 4 instead of 2 ?!
Can someone plz explain why does the alert print 4?
If I created a new instance of my function, the stuff property should be empty.

What you are doing here is generally considered bad practice. You don't want to overwrite the prototype, but you want to add to it.
Now to core of your problem. You are defining stuff as an attribute to the prototype. That means any object that is created using that prototype will share that object. If you want each instance to have it's own stuff, it needs to be an instance variable:
function myclass(){
this.stuff = {};
}
myclass.prototype = {
getStuff: function(){
return Object.keys(this.stuff).length;
}
};
But like I said, don't redefine the prototype, add onto it:
function myclass(){
this.stuff = {};
}
myclass.prototype.getStuff = function(){
return Object.keys(this.stuff).length;
}
Now, anything added to stuff will only be added to that particular instance:
var foo = new myclass();
foo.stuff.thing = "Hey, I'm foo";
var bar = new myclass();
bar.stuff.thing = "Hey, I'm bar";
console.log(bar.stuff); //{thing: "Hey, I'm bar"}

Related

Javascript prototype method "Cannot set property"

I'm always getting Cannot set property 'saySomething' of undefined but why?
Am I making a mistake somewhere?
var Person = new Object();
Person.prototype.saySomething = function ()
{
console.log("hello");
};
Person.saySomething();
Debugging tip: You get this ..of undefined errors when you try to access some property of undefined.
When you do new Object(), it creates a new empty object which doesn't have a prototype property.
I am not sure what exactly are we trying to achieve here but you can access prototype of function and use it.
var Person = function() {};
Person.prototype.saySomething = function() {
console.log("hello");
};
var aperson = new Person();
aperson.saySomething();
The prototype property exists on functions, not on instantiated objects.
var Person = new Object();
console.log(Person.prototype); // undefined
var Person2 = function () {}
console.log(Person2.prototype); // {}
This is useful because things put on the prototype of a function will be shared by all object instances created with that function (by using new).
var Person = function() {};
Person.prototype.saySomething = function() {
console.log("hello");
};
console.log(
new Person().saySomething === Person.prototype.saySomething // true. they are the same function
);
If all you want is to add a method to the person object, there's no need for a prototype:
var Person = {};
Person.saySomething = function() {
console.log("hello");
};
Person.saySomething();
You can even use object literal syntax:
var Person = {
saySomething: function() {
console.log("hello");
}
};
Person.saySomething();
i was trying out some code thought of posting it, might help others.
<script>
var MODULE = {};
MODULE = (function (my) {
my.anotherMethod = function () {
console.log("hello ");
};
my.newMethod = function(){
console.log("hi new method ");
}
return my;
}(MODULE));
MODULE.anotherMethod();
MODULE.newMethod();
</script>
And please not var MODULE ={}, if this is not initialized with {} then it give cannot set property.
I know i am late to the party but as you see there is no satisfying answer available to the question so i am providing my own.
In your case when you write
var Person = new Object();
you are creating an instance of Object type.
You can add a property using prototype property to the Object, not to the instance of Object.which you can use by the instance laterly.
so you can define like
Object.prototype.saySomething = function ()
{
console.log("hello");
};
now you can call it like this.
Person.saySomething();
You can check here.
var Person = function(name) {
this.canTalk = true;
this.name = name;
};
Person.prototype.greet = function() {
if (this.canTalk) {
console.log('Hi, I am ' + this.name);
}
};
bob = new Person('bob');
bob.greet();

Issue when trying to inherit all classes referenced by name in a for loop

Well the title is a mouthful but I couldn't come up with a better one, ideas welcome.
Anyhow, I have a javascript object containing classes as properties. I want to create another object which is in every aspect equal to the first one by subclassing it. I'm gonna try to sum it up:
var L1 = {};
L1.Foo = function() {/*...*/};
L1.Bar = function() {/*...*/};
//...
L1.Baz = function() {/*...*/};
var L2 = {};
L2.Foo = function() { L1.Foo.call(this); /*possibily some other code here*/ };
L2.Foo.prototype = Object.create(L1.Foo.prototype);
L2.Foo.prototype.constructor = L2.Foo;
L2.Bar = function() { L1.Bar.call(this); /*possibily some other code here*/ };
L2.Bar.prototype = Object.create(L1.Bar.prototype);
L2.Bar.prototype.constructor = L2.Bar;
//...
L2.Baz = function() { L1.Baz.call(this); /*possibily some other code here*/ };
L2.Baz.prototype = Object.create(L1.Baz.prototype);
L2.Baz.prototype.constructor = L2.Baz;
var foo = new L2.Foo();
console.log(foo); //L2.Foo
var bar = new L2.Bar();
console.log(bar); //L2.Bar
var baz = new L2.Baz();
console.log(baz); //L2.Baz
First, working version.
I told myself: "huh, looks like there a pattern here" so I went and modified my code as follows:
//first 10 lines unaltered
for(prop in L1) {
L2[prop] = function() { L1[prop].call(this); /*Call super method by default,
unless overriden below*/ };
L2[prop].prototype = Object.create(L1[prop].prototype);
L2[prop].prototype.constructor = L2[prop];
}
//Here I decide that I want to override only the constructor
//for Foo, so naturally:
L2.Foo.prototype.constructor = function() {
L1.Foo.call(this);
this.someOtherProperty = "foo";
};
var foo = new L2.Foo();
console.log(foo); //L2.(anonymous function)?
console.log(foo.someOtherProperty); //undefined?
var bar = new L2.Bar();
console.log(bar); //L2.(anonymous function)?
var baz = new L2.Baz();
console.log(baz); //L2.(anonymous function)?
Second, not-so-working version.
What I am getting wrong?
"huh, looks like there a pattern here" so I went and modified my code
as follows:
for(prop in L1) {
L2[prop] = function() { L1[prop].call(this);
You've hit the common closure in a loop problem - all your L2 functions are actually calling L1.Baz on their new instance as prop will have the value "Baz". See the linked question for how to fix this.
Also, notice that none of your constructors does pass its arguments to the super call, which might bite you as well.
Here I decide that I want to override only the constructor for Foo, so
naturally:
L2.Foo.prototype.constructor = function() {
L1.Foo.call(this);
this.someOtherProperty = "foo";
};
What I am getting wrong?
Overwriting the .constructor property on a prototype object does nothing. Your code is still invoking new L2.Foo, not new L2.Foo.prototype.constructor. You might want to have a look at how the new keyword works.
Instead, you really need to replace L2.Foo. This can be done with this pattern:
L2.Foo = (function (original) {
function Foo() {
original.apply(this, arguments); // apply old L2.Foo constructor
this.someOtherProperty = "foo"; // set property
}
Foo.prototype = original.prototype; // reset prototype
Foo.prototype.constructor = Foo; // fix constructor property
return Foo;
})(L2.Foo);
(or you just put your standard pattern from the first version). If this does get too repetitive, you might also do the .prototype and .constructor setup programmatically:
// whole code
var L2 = {
Foo: function() {
L1.Foo.call(this);
this.someOtherProperty = "foo";
}
// … other overwritten constructors
};
for (var prop in L1) {
if (!L2[prop]) // unless overridden above, create default that only…
(function(parent) {
L2[prop] = function() {
parent.apply(this, arguments); // calls super
};
}(L1[prop]));
L2[prop].prototype = Object.create(L1[prop].prototype);
L2[prop].prototype.constructor = L2[prop];
}
This might just be me, but if the subclass needs to be the same in every aspect as the superclass, why bother making a subclass? I'm not entirely clear an what you are trying to achieve from the code.
But just give the class a property of the class itself
e.g. (in plain java)
public class TestInheritClass {
private TestInheritClass tic;
public TestInheritClass getTic() {
return tic;
}
public void setTic(TestInheritClass tic) {
this.tic = tic;
}
}

Run additional action after constructor

Is it possible to change a constructor so that some extra action is run after an object is created. I tried something like:
var origFoo = Foo
Foo = function() {
origFoo.apply(this, arguments);
/* extra actions */
}
Foo.prototype = new origFoo();
but this has several problems like the constructor being run twice or changing the prototype chain.
You are very close. You should assign the Foo.prototype to the origFoo.prototype in order to get the same prototype chain. Everything else is spot on!
Example:
var Foo = function () {
console.log('OriginalFoo');
};
Foo.prototype.method1 = function () {
console.log('Method1');
};
OriginalFoo = Foo;
Foo = function () {
OriginalFoo.apply(this, arguments);
console.log('NewFoo');
};
Foo.prototype = OriginalFoo.prototype;
Foo.prototype.method2 = function () {
console.log('Method2');
};
var x = new Foo();
x.method1();
x.method2();
Demo: http://jsbin.com/ibatah/1/edit?js,console,output
PS: There still is the problem of static-like properties (Foo.prop), but i'm afraid i don't have a solution for that other than copying them one at a time.
EDIT: Solution for special constructors.
Indeed there are constructors which don't like to be called as functions ex: Image. To get over it, you can do the more awkard solution below. You take advantage of the fact that you can return an object from the constructor and it takes the place of the one created with new. In the overridden constructor you must always use this new object when calling methods instead of this.
var Foo = function(a,b,c) {
console.log('OriginalFoo',a,b,c);
};
Foo.prototype.prop1 = 'Property1';
Foo.prototype.method1 = function() {
console.log('Method1', this.prop1);
};
OriginalFoo = Foo;
Foo = function(a,b,c) {
var obj = new OriginalFoo(a,b,c);
obj.init('Changed...'); // or this.init.call(obj,'Changed!');
this.init('Not Changed'); // applies to a discarded object, has no effect
console.log('NewFoo');
return obj;
};
Foo.prototype = OriginalFoo.prototype;
Foo.prototype.prop2 = 'Property2';
Foo.prototype.method2 = function() {
console.log('Method2', this.prop2);
};
Foo.prototype.init = function(param) {
this.prop2 = param;
};
var x = new Foo('1','2','3');
console.log(x.prop1);
console.log(x.prop2);
x.method1();
x.method2();
Demo: http://jsbin.com/ibatah/2/edit?js,console,output

How do I monkey patch an object's constructor function?

I'd like to monkey patch the constructor for this 'Controller' object. But how do I monkey patch the constructor function so I can still call the original? This is what I've tried.
// original
function Controller() {
this._tag = 'div';
}
Controller.prototype.tag = function() {
console.log(this._tag);
}
var c = new Controller();
c.tag(); // -> 'div', as expected
// patch attempt
var original = Controller;
Controller = function() {
original.apply(this);
this._tag = 'patched'; // patch
}
var c = new Controller();
c.tag(); // no method tag, prototype appears wiped...
You seem to want to do something like:
Constructor.prototype.oldTag = Constructor.prototype.tag;
Constructor.prototype.tag = function() {/* whatever */};
Now all instances get the new tag method and you can still call oldTag if you want (or put it back).
Or perhaps you want to do something like:
var oldConstructor = Constructor;
var Constructor = function () { /* new constructor */ };
Constructor.prototype = oldConstructor.prototype;
So now you have a new constructor with all the old methods. Or do both the above. Just use plain English to say what you want to do.
The cleaner way is not monkey patching the constructor: put the constructor logic in a separate init method and monkey patch / inherit that instead.
function Constructor(){
this.init();
}
Constructor.prototype.init = function(){ /*...*/ };
You can also consider building objects with a builder function
function make_fancy_obj(){
var obj = new Constructor();
obj.foo = 'bar';
return obj;
}
Constructor functions may optionally return a different this, which will override whatever is generated by the new statement itself - here's your example corrected and annotated:
// original
function Controller() {
this._tag = 'div';
}
Controller.prototype.tag = function() {
console.log(this._tag);
}
var c = new Controller();
c.tag(); // -> 'div', as expected
// patch attempt
var original = Controller;
Controller = function() {
const instance = new original(...arguments); // πŸ‘ˆ call the original constructor
instance._tag = 'patched'; // patch
return instance; // πŸ‘ˆ return your replacement instance
}
var c = new Controller();
c.tag(); // πŸ‘ works
You can try it here:
https://jsfiddle.net/mindplay/qc8Lf7ae/

Javascript prototypal inheritance and OOP

I'm creating an application that allows a user to create widgets. There are several different types of widgets, and I have defined them using protypal inheritance. i.e.
//the base widget that all widgets inherit from
var Widget = function(){}
Widget.prototype.someFunction = function(){}
//widget type A
var A = function(){}
A.prototype = new Widget();
//widget type B
var B = function(){}
B.prototype = new Widget();
I have discovered that it will be convenient to add a method on the base class that can create a new widget instance of the same type. i.e.
//the base widget
var Widget = function(){};
Widget.prototype.clone = function(){
switch(this.type){
case 'A':
return new A();
break;
case 'B':
return new B();
break;
default:
break;
}
};
Which would allow me to get a new widget of the same type using the following code:
var widgetTypeA = new A();
var cloneOfWidgetTypeA = widgetTypeA.clone();
My concern is that the base widget now has to be explicitly aware of each of the types of widgets that inherit from it. Does this violate any principles of good OOP?
Widget.prototype.clone = function() {
var constructor = window[this.type];
return new constructor();
};
Assuming that all your subclasses are declared as globals of course.
But honestly I would out those sub classes in the Widget namespace, and access them through it rather than making everything global.
Widget.A = function(){};
Widget.A.prototype = new Widget();
Widget.prototype.clone = function() {
var constructor = Widget[this.type];
return new constructor();
};
Given that your constructors are globals, you could do something like:
var global = this;
Widget.prototype.clone = function() {
if (global[this.type])
return new global[this.type]();
};
Provided each instance has a type property whose value is the name of the constructor. Or you could fix the constructor property of constructor's prototype and do:
Widget.prototype.clone = function() {
return new this.constructor();
};
function A() { };
A.prototype = new Widget();
A.prototype.constructor = A;
var a = new A();
var aa = a.clone();
However, that assumes that you don't have any parameters to pass. If you do have parameters to pass, then you likely have to know which type you are making and so can call the correct constructor anyway.
If ECMA5 is supported:
use Object.create(Object.getPrototypeOf(this));
If ECMA5 is not supported:
create an anonymous function
set the prototype of the anonymous function to the non-standard attribute this.__proto__
Example:
var Widget = function() { };
Widget.prototype.clone = function() {
/*
Non-ECMA5:
var newClone = function() {};
newClone.prototype = this.__proto__;
return new newClone();
*/
// ECMA5
return Object.create(Object.getPrototypeOf(this));
}
var A = function() { };
A.prototype = new Widget();
A.prototype.name = "I'm an A";
var B = function() { };
B.prototype = new Widget();
B.prototype.name = "I'm a B";
var x1 = new A();
var y1 = x1.clone();
console.log("y1 should be A: %s", y1.name);
var x2 = new B();
var y2 = x2.clone();
console.log("y2 should be B: %s", y2.name);
The information you need is already available in the constructor property. However, overwriting prototype will lose it as I recently explained here.
Using my own class implementation for ECMAScript version 3 or version 5, your example would look like this:
var Widget = Class.extend({
someFunction : function() {
alert('someFunction executed');
},
clone : function() {
return new this.constructor;
}
});
var A = Widget.extend();
var B = Widget.extend({
constructor : function(arg) {
Widget.call(this); // call parent constructor
this.arg = arg;
},
// override someFunction()
someFunction : function() {
alert('someFunction executed, arg is ' + this.arg)
},
// clone() needs to be overriden as well:
// Widget's clone() doesn't know how to deal with constructor arguments
clone : function() {
return new this.constructor(this.arg);
}
});
var a = new A;
var a2 = a.clone();
a2.someFunction();
var b = new B(42);
var b2 = b.clone();
b2.someFunction();

Categories

Resources