Run additional action after constructor - javascript

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

Related

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;
}
}

Callback when 'class' instance is created

var foo = (function(){
var c = function(requests) {
bar();
};
c.prototype = {
bar: bar
};
return c;
})();
var f = new foo();
f.baz(function(){
console.log('new instance of foo created');
});
http://jsfiddle.net/LecJM/
I would like to create a callback function which is called when a new instance of the "class" foo is created. Is this possible? Obviously the code above won't compile, I just want to give you an idea of what I'm trying to achieve.
var Foo = function (createdCallback) {
createdCallback();
return this;
};
var bar = new Foo(function () {
console.log("instance created");
});
Is this what you want to achieve?
Something like this?
var foo = (function(){
var c = function(requests) {
// Initialize your instance
// ...
// Notify
notifyCreated(this);
};
c.prototype = { ... };
var createdCallbacks = [];
c.onCreate = function(callback) {
createdCallbacks.push(callback);
}
function notifyCreated(instance) {
// Note: forEach requires ES5 or a shim
// Just use whatever you want to loop over the array
createdCallbacks.forEach(function(callback) {
callback(instance);
});
}
return c;
})();
// Add callback *before* creating instances
foo.onCreate(function(instance){
console.log('new instance of foo created', instance);
});
// Create an instance
var f = new foo();
Basically, you add a method to foo (and not to foo.prototype) to add a callback. Inside your constructor, you call all registered callbacks (here demonstrated with a separate internal function). To use, you first register a callback and then start creating instances.
EDIT: As requested, with just one callback:
var foo = (function(){
var c = function(requests) {
// Initialize your instance
// ...
// Notify
notifyCreated(this);
};
c.prototype = { ... };
// Use a dummy callback by default
var notifyCreated = function(){};
c.onCreate = function(callback) {
notifyCreated = callback;
}
return c;
})();
Demo
EDIT 2: Heck, if you're only going to need one callback, you might as well get rid of the onCreate function and just expose the callback as a variable. There are a few downsides to this though:
You can't do input checking, for example you can't test if the callback is actually a function before storing it.
Others can trigger the callback externally through foo.onCreate(anInstance).
If those are not problematic (for example if you're not exposing foo anyway), feel free to use this extremely simple snippet:
var foo = (function(){
var c = function(requests) {
// Initialize your instance
// ...
// Trigger callback
c.onCreate(this);
};
c.prototype = { ... };
// Expose callback on "class"
c.onCreate = function(){};
return c;
})();
// Set callback *before* creating instances
foo.onCreate = function(instance){
console.log('new instance of foo created', instance);
};
// Create an instance
var f = new foo();
Demo
Try this
var foo = function() {
this.baz();
};
foo.prototype.baz = function () {
console.log('new instance of foo created');
};
var f = new foo();

Creating a new empty object in JavaScript

When trying to create a new object, one that is empty for manipulation, I can't get the old data out.
Here is an example of what I've tried:
function Foo() {
this.Bar = Bar;
// etc..
}
var Bar = {
__words : {},
addWord : function (word, amount) {
this.__words[word] = amount;
}
// etc..
}
Now, when I create a new object:
var foo = new Foo();
var bar = foo.Bar;
bar.addWord("hello",7);
bar.addWord("world",9);
var lorem = new Foo();
var words = lorem.Bar.__words; // This will display {hello:7,world:9} from the
// previous object
I also tried using Object.create() but it was still the same, showing the __words from the previous object.
The object referred to by Bar is shared between each Foo instance.
I don't really see the point of putting the logic into two objects, you can do this with just one constructor function:
function Foo() {
this.__words = {};
}
Foo.prototype.addWord = function(word, amount) {
this.__words[word] = amount;
}
var foo = new Foo();
foo.addWord("hello",7);
var bar = new Foo();
bar.addWord("world",9);
If you really have to separate the functionality, then make Bar a constructor function as well and create a new instance inside the Foo constructor method:
function Foo() {
this.bar = new Bar();
}
function Bar() {
this.__words = {};
}
Bar.prototype.addWord = function(word, amount) {
this.__words[word] = amount;
}
There are couple of problems in the code.
function Foo() {
this.Bar = Bar;
// etc..
}
var Bar = {
__words : {},
addWord : function (word, amount) {
this.__words[word] = amount;
}
// etc..
}
Bar should be defined before Foo but it might work without problems because variables are actually defined at function scope level which might not be a problem in this particular example.
That said, you're copying an object inside the Foo constructor. Objects are mutables so it won't work. One change to the object will change the other. What you might be able to do is this. Here's an other way to do that without new.
var Bar = {
create: function () {
var obj = Object.create(this);
obj.__words= {};
return obj;
},
addWord: function (word, amount) {
this.__words[word] = amount;
}
...other methods...
};
var Foo = function () {
this.Bar = Bar.create();
// etc..
};
But I have no idea how is supported Object.create in other browsers. This is syntax is the equivalent to what Felix wrote, you could clearly remove the need of two object.
The only big difference is that instead of writing new Bar(). You are actually creating a prototype object and creating an object from the prototype. The create is the constructor.
Foo could be written in the same way and you'd get something like this.
var Bar = {
create: function () {
var obj = Object.create(this);
obj.__words= {};
return obj;
},
addWord: function (word, amount) {
this.__words[word] = amount;
},
...other methods...
};
var Foo = {
create: function () {
var foo = Object.create(this);
foo.Bar = Bar.create();
return foo;
},
....
};
var foo1 = Foo.create();
var foo2 = Foo.create();
foo1.bar.addWord("allo", 3);
I guess it all depends on what you're trying to do but the create method as some advantages over the "new" operators. You could for example create async methods that after object creations execute a callback.
Over here for more informations. In the end it's pretty much the same thing.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
I can't get the old data out.
Well you are not clearing var Bar which is global actually - meaning you are creating a new Object with var lorem = new Foo(); but giving him the same Bar Object with Foos constructor.
this.Bar = Bar;
if you want a new Object you should give Foo its own Bar Object.
Or include:
__words : {},
addWord : function (word, amount) {
this.__words[word] = amount;
in Foo itself.
Anyways if you just need this once, you could simply empty the words array in Bar.

avoid needing to declare 'var me = this' for javascript prototype functions

Currently, I create objects in javascript by declaring a construction (regular function) then add methods to the prototype like so
function Test(){
}
Test.prototype.test1 = function(){
var me = this;
}
However, I would like to avoid having to declare var me = this at the top of every function. The following seems to work, but seems like it would be very inefficient:
$(document).ready(function(){
var n = 0;
(function(){
function createTest(){
var me;
function Test(){
this.n = n;
this.testArr = [1, 2, 3, 4];
n++;
}
Test.prototype.test1 = function(){
me.test2();
};
Test.prototype.test2 = function(){
alert(me.n);
$.getJSON('test.php', {}, function(reply)
//want to be able to use 'me' here
me.newField = reply;
});
};
var t = new Test();
me = t;
return t;
}
window['createTest'] = createTest;
})();
var t = createTest();
t.test1();
var t2 = createTest();
t2.test1();
t.test1();
});
This code outputs the expected, but is it actually as inefficient as it looks (the Test object being re-declared every time you call createTest())?
Anyhoo, this would seem a bit hacky... is there a completely different way to do this that is better?
EDIT: The real reason I would like to do this is so that callbacks like the one in test2 will have references to the correct this.
What you can do is bind the current this value to a function and store a copy somewhere. (For the sake of efficiency.)
if (!Function.prototype.bind) {
// Most modern browsers will have this built-in but just in case.
Function.prototype.bind = function (obj) {
var slice = [].slice,
args = slice.call(arguments, 1),
self = this,
nop = function () { },
bound = function () {
return self.apply(this instanceof nop ? this : (obj || {}),
args.concat(slice.call(arguments)));
};
nop.prototype = self.prototype;
bound.prototype = new nop();
return bound;
};
}
function Test(n) {
this.n = n;
this.callback = (function () {
alert(this.n);
}).bind(this)
}
Test.prototype.test1 = function () {
this.test2();
}
Test.prototype.test2 = function () {
doSomething(this.callback);
}
function doSomething(callback) {
callback();
}
var t = new Test(2);
t.test1();
I realize your question was not tagged with jQuery, but you are using it in your example, so my solution also utilizes jQuery.
I sometimes use the $.proxy function to avoid callback context. Look at this simple jsfiddle example. Source below.
function Test(){
this.bind();
}
Test.prototype.bind = function(){
$('input').bind('change', $.proxy(this.change, this));
// you could use $.proxy on anonymous functions also (as in your $.getJSON example)
}
Test.prototype.change = function(event){
// currentField must be set from e.target
// because this is `Test` instance
console.log(this instanceof Test); // true
console.log(event.target == $('input')[0]); // true
this.currentField = event.target; // set new field
};
function createTest(){
return new Test();
}
$(function(){ // ready callback calls test factory
var t1 = createTest();
});
Most of the time, I just declare a local variable that references this, wherever I need a reference to this in a callback:
function Foo() {
}
Foo.prototype.bar = function() {
var that=this;
setTimeout(function() {
that.something="This goes to the right object";
}, 5000);
}
Alternatively, you can use bind() like this:
Function Foo() {
this.bar = this.bar.bind(this);
// ... repeated for each function ...
}
Foo.prototype.bar = function() {
}
What this gives you is that every time you create a new Foo instance, the methods are bound to the current instance, so you can use them as callback functions for setTimeout() et al.

Calling method using JavaScript prototype

Is it possible to call the base method from a prototype method in JavaScript if it's been overridden?
MyClass = function(name){
this.name = name;
this.do = function() {
//do somthing
}
};
MyClass.prototype.do = function() {
if (this.name === 'something') {
//do something new
} else {
//CALL BASE METHOD
}
};
I did not understand what exactly you're trying to do, but normally implementing object-specific behaviour is done along these lines:
function MyClass(name) {
this.name = name;
}
MyClass.prototype.doStuff = function() {
// generic behaviour
}
var myObj = new MyClass('foo');
var myObjSpecial = new MyClass('bar');
myObjSpecial.doStuff = function() {
// do specialised stuff
// how to call the generic implementation:
MyClass.prototype.doStuff.call(this /*, args...*/);
}
Well one way to do it would be saving the base method and then calling it from the overriden method, like so
MyClass.prototype._do_base = MyClass.prototype.do;
MyClass.prototype.do = function(){
if (this.name === 'something'){
//do something new
}else{
return this._do_base();
}
};
I'm afraid your example does not work the way you think. This part:
this.do = function(){ /*do something*/ };
overwrites the definition of
MyClass.prototype.do = function(){ /*do something else*/ };
Since the newly created object already has a "do" property, it does not look up the prototypal chain.
The classical form of inheritance in Javascript is awkard, and hard to grasp. I would suggest using Douglas Crockfords simple inheritance pattern instead. Like this:
function my_class(name) {
return {
name: name,
do: function () { /* do something */ }
};
}
function my_child(name) {
var me = my_class(name);
var base_do = me.do;
me.do = function () {
if (this.name === 'something'){
//do something new
} else {
base_do.call(me);
}
}
return me;
}
var o = my_child("something");
o.do(); // does something new
var u = my_child("something else");
u.do(); // uses base function
In my opinion a much clearer way of handling objects, constructors and inheritance in javascript. You can read more in Crockfords Javascript: The good parts.
I know this post is from 4 years ago, but because of my C# background I was looking for a way to call the base class without having to specify the class name but rather obtain it by a property on the subclass. So my only change to Christoph's answer would be
From this:
MyClass.prototype.doStuff.call(this /*, args...*/);
To this:
this.constructor.prototype.doStuff.call(this /*, args...*/);
if you define a function like this (using OOP)
function Person(){};
Person.prototype.say = function(message){
console.log(message);
}
there is two ways to call a prototype function: 1) make an instance and call the object function:
var person = new Person();
person.say('hello!');
and the other way is... 2) is calling the function directly from the prototype:
Person.prototype.say('hello there!');
This solution uses Object.getPrototypeOf
TestA is super that has getName
TestB is a child that overrides getName but, also has
getBothNames that calls the super version of getName as well as the child version
function TestA() {
this.count = 1;
}
TestA.prototype.constructor = TestA;
TestA.prototype.getName = function ta_gn() {
this.count = 2;
return ' TestA.prototype.getName is called **';
};
function TestB() {
this.idx = 30;
this.count = 10;
}
TestB.prototype = new TestA();
TestB.prototype.constructor = TestB;
TestB.prototype.getName = function tb_gn() {
return ' TestB.prototype.getName is called ** ';
};
TestB.prototype.getBothNames = function tb_gbn() {
return Object.getPrototypeOf(TestB.prototype).getName.call(this) + this.getName() + ' this object is : ' + JSON.stringify(this);
};
var tb = new TestB();
console.log(tb.getBothNames());
function NewClass() {
var self = this;
BaseClass.call(self); // Set base class
var baseModify = self.modify; // Get base function
self.modify = function () {
// Override code here
baseModify();
};
}
An alternative :
// shape
var shape = function(type){
this.type = type;
}
shape.prototype.display = function(){
console.log(this.type);
}
// circle
var circle = new shape('circle');
// override
circle.display = function(a,b){
// call implementation of the super class
this.__proto__.display.apply(this,arguments);
}
If I understand correctly, you want Base functionality to always be performed, while a piece of it should be left to implementations.
You might get helped by the 'template method' design pattern.
Base = function() {}
Base.prototype.do = function() {
// .. prologue code
this.impldo();
// epilogue code
}
// note: no impldo implementation for Base!
derived = new Base();
derived.impldo = function() { /* do derived things here safely */ }
If you know your super class by name, you can do something like this:
function Base() {
}
Base.prototype.foo = function() {
console.log('called foo in Base');
}
function Sub() {
}
Sub.prototype = new Base();
Sub.prototype.foo = function() {
console.log('called foo in Sub');
Base.prototype.foo.call(this);
}
var base = new Base();
base.foo();
var sub = new Sub();
sub.foo();
This will print
called foo in Base
called foo in Sub
called foo in Base
as expected.
Another way with ES5 is to explicitely traverse the prototype chain using Object.getPrototypeOf(this)
const speaker = {
speak: () => console.log('the speaker has spoken')
}
const announcingSpeaker = Object.create(speaker, {
speak: {
value: function() {
console.log('Attention please!')
Object.getPrototypeOf(this).speak()
}
}
})
announcingSpeaker.speak()
No, you would need to give the do function in the constructor and the do function in the prototype different names.
In addition, if you want to override all instances and not just that one special instance, this one might help.
function MyClass() {}
MyClass.prototype.myMethod = function() {
alert( "doing original");
};
MyClass.prototype.myMethod_original = MyClass.prototype.myMethod;
MyClass.prototype.myMethod = function() {
MyClass.prototype.myMethod_original.call( this );
alert( "doing override");
};
myObj = new MyClass();
myObj.myMethod();
result:
doing original
doing override
function MyClass() {}
MyClass.prototype.myMethod = function() {
alert( "doing original");
};
MyClass.prototype.myMethod_original = MyClass.prototype.myMethod;
MyClass.prototype.myMethod = function() {
MyClass.prototype.myMethod_original.call( this );
alert( "doing override");
};
myObj = new MyClass();
myObj.myMethod();

Categories

Resources