using function caller names in method chaining - javascript

I have the following Pet and cat inherits from Pet, as follows:
function Pet(){};
Pet.prototype.run = function takeoff(cb, sec) {
setTimeout(function() {
cb();
console.log('Run');
}, sec);
};
Pet.prototype.bark = function bark(cb, sec) {
setTimeout(function() {
cb();
console.log('bark');
}, sec);
};
Pet.prototype.comeback = function comeback(cb, sec) {
setTimeout(function() {
cb();
console.log('Comeback');
}, sec);
};
var cat = new Pet();
cat.prototype = Object.create(Pet);
cat.prototype.run = function(){
var that = this;
that.run = Pet.prototype.run.call(that);
return that;
}
cat.prototype.bark = function(){
this.bark = Pet.prototype.bark.call(this);
return this;
}
cat.prototype.comeback = function(){
this.comeback = Pet.prototype.comeback.call(this);
return this;
}
console.log(cat);
cat.run().bark().return();
In this situation, the cat and Pet have the same function names. The only difference is return this is added to cat methods to make method chaining possible in cat but not Pet. However, note that I have to write the name of the function every time and set the same name to its parent's prototype. Is it possible to generalize this so that any method I specify for Pet will be duplicated in cat but yet I don't have to specify the method for cat every time?

After a discussion with guest I came up with a solution that extends each function to use a promise. The code will be executed in order and the object will be chained.
function Pet(){};
Pet.prototype.run = function run(callback) {
setTimeout(function() {
callback()
console.log('Run');
}, 1000);
};
Pet.prototype.bark = function bark(callback) {
setTimeout(function() {
callback()
console.log('Bark');
}, 500);
};
Pet.prototype.comeBack = function comeBack(callback) {
setTimeout(function() {
callback()
console.log('Comeback');
}, 750);
};
// DON'T MODIFY ANYTHING ABOVE HERE
// START ADD YOUR CODE HERE
function createChainableFunction(fun) {
var that = this;
return function() {
if(!that.promise) {
that.promise = new Promise(function(resolve, reject) {
fun.call(that, resolve);
});
}
else {
that.promise.then(function() {
that.promise = new Promise(function(resolve) {
fun.call(that, resolve);
});
});
}
return this;
}
}
function isFunction(functionToCheck) {
var getType = {};
return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
}
function createChainable(object) {
var chainable = {
'promise': null
};
chainable.prototype = Object.getPrototypeOf(object);
for(var prop in object) {
if(isFunction(object[prop])) {
chainable[prop] = createChainableFunction.call(chainable.prototype, object[prop], prop);
}
}
return chainable;
}
var cat = createChainable(new Pet());
cat.run().bark().comeBack();

You can add a property in child classes and based on this value, you can return this.
Sample
// Parent Class
function Pet() {
this.sec = 1000
};
Pet.prototype.run = function takeoff(cb, sec) {
setTimeout(function() {
//cb();
console.log('Run');
}, sec || this.sec);
if (this.animalName) return this;
};
Pet.prototype.bark = function bark(cb, sec) {
setTimeout(function() {
//cb();
console.log('bark');
}, sec || this.sec);
if (this.animalName) return this;
};
Pet.prototype.comeback = function comeback(cb, sec) {
setTimeout(function() {
//cb();
console.log('Comeback');
}, sec || this.sec);
if (this.animalName) return this;
};
// Child class
var Cat = function() {
this.animalName = 'Cat'
}
// Linking of classes
Cat.prototype = new Pet();
// object of child class
var cat = new Cat();
cat.run().bark().comeback()
var pet = new Pet();
try {
// Chaining not allowed.
pet.run().bark().comeback()
} catch (ex) {
console.log(ex.message)
}

Related

JavaScript: Executing chained methods in any order

Suppose I have a function called log which simply prints the given string.
Can I refactor my code so both of these function could work?
log("needsChange").doSomethingWithTheStringBeforePrintingIt();
log("perfectStringToPrint");
You can do something similar with nested class logics:
var log = (function() {
//Class
var _log = (function() {
function _log(message) {
this.message = message;
}
_log.prototype.doSomethingWithTheStringBeforePrintingIt = function() {
this.message = this.message.split("").reverse().join("");
return this;
};
_log.prototype.capitalizeFirstWord = function() {
this.message = this.message[0].toUpperCase() + this.message.substr(1);
return this;
};
_log.prototype.print = function() {
return this.message;
};
return _log;
}());
//Instancer function
return function log(message) {
//Return instance of class
return new _log(message);
};
})();
//Test
console.log(log("needsChange")
.doSomethingWithTheStringBeforePrintingIt()
.capitalizeFirstWord()
.print(), log("perfectStringToPrint")
.print());
If you are comfortable with promises, then you can do something like this:
var logger = (function() {
//Class
var _log = (function() {
function _log(message) {
var _this = this;
this.message = message;
this.promise = null;
this.promises = [];
this.promise = Promise.all(this.promises).then(function(values) {
console.log(_this.message); // [3, 1337, "foo"]
});
}
_log.prototype.reverse = function() {
var self = this;
this.promises.push(new Promise(function(resolve, reject) {
setTimeout(resolve, 0, (function() {
self.message = self.message.split("").reverse().join("");
})());
}));
return this;
};
_log.prototype.capitalizeFirst = function() {
var self = this;
this.promises.push(new Promise(function(resolve, reject) {
setTimeout(resolve, 0, (function() {
self.message = self.message[0].toUpperCase() + self.message.substr(1);
})());
}));
return this;
};
return _log;
}());
//Instancer function
return function log(message) {
//Return instance of class
return new _log(message);
};
})();
//Test
logger("needsChange").reverse().capitalizeFirst().reverse(); //Capitalizes last letter
logger("perfectStringToPrint");
This removes the need for a .print call.
I have made a library to solve this issue
https://github.com/omidh28/clarifyjs

can't use filter function on array

I learn how to code in javascript. I have always error: "Cannot read property 'filter' of undefined". What am I doing wrong here and why?
I have to build A class with Singleton pattern and B class which will be observer of A class.
I have to add some instances of B class to A as subscribers (observers) and unsubscribe any of it when random value I from A class is bigger than random value P from B class.
var A = (function()
{
// Instance stores a reference to the Singleton
var instance;
function init() {
// Singleton
var i = 0;
let observers = new Array();
function CheckIfGreaterThanI(observer)
{
console.log("CHECKING");
return observer.getP() > this.getI();
}
return {
subscribe: function(observer)
{
console.log("DODAJĘ");
observers.push(observer);
},
unsubscribe: function(observerss)
{
console.log("USUWAM");
for(i=0;i<observerss.length;i++)
{
var index = this.observers.indexOf(observerss[i])
if (~index)
{
this.observers.splice(index, 1);
}
}
},
notify: function()
{
for(let observer of observers)
{
observer.update();
}
},
getI: function()
{
return this.i;
},
setI: function(value)
{
this.i = value;
this.notify();
///THAT'S THE PLACE WHERE ERROR RISES
var observersToUnsubscribe = this.observers.filter(this.CheckIfGreaterThanI);
this.unsubscribe(observersToUnsubscribe);
}
};
};
return
{
// Get the Singleton instance if one exists
// or create one if it doesn't
getInstance: function () {
if ( !instance ) {
instance = init();
}
return instance;
}
};
})();
function B (name,value,a) //observer
{
this.Name = name;
this.P = value;
this.A = a;
}
B.prototype =
{
constructor:B,
getName : function()
{
return this.Name;
},
getP : function()
{
return this.P;
},
update : function()
{
if(A.getInstance().getI()<this.P)
{
console.log("OK - " + this.Name);
}
}
};
for(i=0;i<10;i++)
{
var bObject = new B(i,Math.random(),A.getInstance());
A.getInstance().subscribe(bObject);
}
var ChangeIValue = function()
{
A.getInstance().setI(Math.random());
}
setTimeout(function run()
{
ChangeIValue();
setTimeout(run,1000);
}
, 1000);
OK, I resolved this problem alone and there were many mistakes behind it, so I added my solution for that:
var A = (function()
{
// Instance stores a reference to the Singleton
var instance;
function init() {
// Singleton
var i = 0;
var observers =[];
function CheckIfGreaterThanI(observer)
{
return observer.getP() > i;
}
return {
subscribe: function(observer)
{
observers.push(observer);
},
unsubscribe: function(observersToUnsubscribe)
{
for(let observer of observersToUnsubscribe)
{
var index = observers.indexOf(observer);
if(index!=-1)
{
observers.splice(index,1);
}
}
},
notify: function()
{
for(let observer of observers)
{
observer.update();
}
},
getI: function()
{
return i;
},
setI: function(value)
{
i = value;
this.notify();
var observersToUnsubscribe = observers.filter(CheckIfGreaterThanI);
this.unsubscribe(observersToUnsubscribe);
return;
}
};
};
return {
// Get the Singleton instance if one exists
// or create one if it doesn't
getInstance: function ()
{
if ( !instance )
{
instance = init();
}
return instance;
}
};
})();
function B (name,value,a) //observer
{
this.Name = name;
this.P = value;
this.A = a;
this.getName = function()
{
return this.Name;
};
this.getP = function()
{
return this.P;
};
this.update = function()
{
if(A.getInstance().getI()<this.P)
{
console.log("OK - " + this.Name);
}
};
};
for(j=0;j<10;j++)
{
var bObject = new B(j,Math.random(),A.getInstance());
A.getInstance().subscribe(bObject);
}
var ChangeIValue = function()
{
A.getInstance().setI(Math.random());
}
setTimeout(function run()
{
ChangeIValue();
setTimeout(run,1000);
}
, 1000);

JavaScript Equivalent Of PHP __invoke

I'm developing a small framework (in JS) and for esthetic reasons and simplicity I was wondering if there could be a way to implement something like PHP "__invoke".
For example:
var myClass = function(config) {
this.config = config;
this.method = function(){};
this.execute = function() {
return this.method.apply(this, arguments);
}
}
var execCustom = new myClass({ wait: 100 });
execCustom.method = function() {
console.log("called method with "+arguments.length+" argument(s):");
for(var a in arguments) console.log(arguments[a]);
return true;
};
execCustom.execute("someval","other");
Desired way to execute:
execCustom("someval","other");
Any ideas? Thanks.
if you are ready to use JS pattern, you can do this in following way:
var myClass = function(opts) {
return function(){
this.config = opts.config;
this.method = opts.method;
return this.method.apply(this, arguments);
};
};
var execCustom = new myClass({
config:{ wait: 100 },
method:function() {
console.log("called method with "+arguments.length+" argument(s):");
for(var a in arguments) console.log(arguments[a]);
return true;
}});
execCustom("someval","other");
jsbin
this is the best way I can think of
UPDATED VERSION (by op)
var myClass = function(opts) {
var x = function(){
return x.method.apply(x, arguments);
};
x.config = opts.config;
x.method = opts.method;
return x;
};
var execCustom = new myClass({
config:{ wait: 100 },
method:function() {
console.log("called method with "+arguments.length+" argument(s):");
for(var a in arguments) console.log(arguments[a]);
return true;
}});
execCustom("someval","other");
jsbin
Just return a function that will form the public interface:
function myClass(config)
{
var pubif = function() {
return pubif.method.apply(pubif, arguments);
};
pubif.config = config;
pubif.method = function() { };
return pubif;
}
The rest of the code remains the same.

Simple counter with a listener and callback

I have a simple class below that starts and then updates a count every second. How would I go about adding functionality for it to listen for a specific value and then fire a callback?
function Counter() {
this.currentCount = 0;
}
Counter.prototype.start = function() {
setInterval(this.update, 1000);
};
Counter.prototype.when = function(value, callback) {
callback(value);
};
Counter.prototype.update = function() {
this.currentCount++;
};
In my mind it would work something like this.
var counter = new Counter();
counter.when(50, function(value) {
console.log('We arrived at ' + value + ', the requested value.');
});
counter.start();
This is just a nice homework, I'll do that for you ;) Please have a look on my solution:
function Counter() {
this.currentCount = 0;
this.conditions = [];
this.interval = undefined;
}
Counter.prototype.start = function() {
if (!this.interval) {
var that = this;
this.interval = setInterval(function () {
that.update();
}, 1000);
}
};
Counter.prototype.stop = function () {
if (this.interval) {
clearInterval(this.interval);
this.interval = undefined;
}
this.currentCount = 0;
};
Counter.prototype.when = function(value, callback) {
var that = this;
this.conditions.push(function () {
if (that.currentCount === value) {
callback.call(that, value);
}
});
};
Counter.prototype.update = function() {
this.currentCount++;
for (var i = 0, l = this.conditions.length; i < l; i++) {
var condition = this.conditions[i];
condition();
}
};
var counter = new Counter();
counter.when(50, function(value) {
console.log('We arrived at ' + value + ', the requested value.');
});
counter.when(60, function (value) {
console.log('Stop at ' + value + '!');
this.stop();
});
counter.start();
and it's fiddled!
Another answer here made a good argument in hiding private variables, but implemented it a bit too confused, so this is another way of doing it similar. Instead of shared prototype functions this is using instance functions. Some may say this needs more memory, but I don't believe it's significant, and allows to easily have privates in a real constructor function.
var Counter = function () {
var that = this, currentCount = 0,
conditions = [], interval;
var update = function () {
currentCount++;
for (var i = 0, l = conditions.length; i < l; i++) {
var condition = conditions[i];
condition();
}
};
this.start = function () {
if (!interval) {
interval = setInterval(function() {
update.call(that);
}, 1000);
}
};
this.when = function (value, callback) {
conditions.push(function () {
if (currentCount === value) {
callback.call(that, value);
}
});
};
this.stop = function () {
if (interval) {
clearInterval(interval);
interval = undefined;
}
currentCount = 0;
};
};
var counter = new Counter();
counter.when(50, function(value) {
console.log('We arrived at ' + value + ', the requested value.');
});
counter.when(60, function (value) {
console.log('Stop at ' + value + '!');
this.stop();
});
counter.start();
see it fiddled!
Notice also that in both examples, counter is instanceof Counter and Object,
whereas Counter is instanceof Function and Object (why I like to write so much code ;))
To support multiple whens:
Add an array of whens in your class:
function Counter() {
this.currentCount = 0;
this.whens = [];
}
Then let the when function push to that:
Counter.prototype.when = function(value, callback) {
this.whens.push({'time' : value, 'callback' : callback});
}
And check for these whens at update:
Counter.prototype.update = function() {
this.currentCount++;
for(var w in this.whens) {
if(this.currentCount == this.whens[w].time) {
this.whens[w].callback();
}
}
}
Try something more like:
function Counter(interval, val, func){
this.currentCount = 0;
setInterval(function(){
this.currentCount++;
if(this.currentCount === val)func();
}, interval);
}
var nc = new Counter(1000, 50, function(){
console.log('We have arrived at '+nc.currrentCount);
});
There is an argument to be made for something like this instead:
var Counter = (function() {
var update = function() {
var idx, callbacks;
this.currentCount++;
callbacks = this.callbacks[this.currentCount];
if (callbacks) {
for (idx = 0; idx < callbacks.length; idx++) {
callbacks[idx](this.currentCount);
}
}
};
var start = function() {
var counter = this;
setInterval(function() {update.call(counter)}, 1000);
};
var when = function(count, callback) {
(this.callbacks[count] || (this.callbacks[count] = [])).push(callback);
};
return function() {
var config = {currentCount: 0, callbacks: {}};
this.start = function() {return start.call(config);};
this.when = function(count, callback) {
return when.call(config, count, callback);
};
// this.stop = ... // if desired
};
}());
This is somewhat more memory intensive than the prototype-based version of the code. I wouldn't use it for something where you were expecting hundreds of thousands or millions of objects. But it has the advantage that it truly encapsulates the data you might like to keep hidden, such as currentCount and the list of callbacks. It doesn't expose an unnecessary update function. And it's not terribly more heavy than the prototype version. Each instance has its own start and when functions, but those are just thin wrappers around common functions.
It is a bit more difficult to add a stop function to this in the same manner, unless you don't mind exposing the the result of setInterval. But it is doable.

javascript: adding function to function inside .prototype = {

If I add a function in the "constructor", I can extend it with an other function like so:
var MyClass = function() {
this.time = function() { return 4.5; }
this.time.formatted = function() { return format(this.time(), "HH:mm"); }
}
I can't figure out a nice way to do this if I create the function in prototype like so:
var MyClass = function() {}
MyClass.prototype = {
time: function() { return 4.5; },
time.formatted: function () { ... } // This does not work!
}
MyClass.prototype.time.formatted = function() { ... }
// the line above works but I don't like it since it separates everything.
// e.g. if I have 15 functions inside prototype, the .formatted will be like
// 50 lines apart from the time: function
*Edit: * On second thoughts the line above does not work, adding the .formatted messes
the reference to this. Perhaps solvable?
Any tips? Thanks!
Create the function before creating the prototype object, that allows you to add a property to it, and also gives you the ability to use the function without using this:
function MyClass() {}
function time() { return 4.5; }
time.formatted = function() { return format(time(), "HH:mm"); }
MyClass.prototype = {
time: time;
}
You can put it in a function expression to keep it together, and avoid having the time function in the global scope:
function MyClass() {}
MyClass.prototype = (function(){
function time() { return 4.5; }
time.formatted = function() { return format(time(), "HH:mm"); }
return {
time: time;
}
})();
Note: The formatted function will be called as a regular function, not as a method of the object. This means that the function time doesn't have access to this when called from the formatted function.
If you need that, you can't have the time function in the prototype at all. Each instance of the class needs its own version of the time function, where the formatted property has access to that specific instance of the object:
function MyClass() {
this.theTime = 4.5;
this.time = function() { return this.theTime; }
var t = this;
this.time.formatted = function() { return format(t.time(), "HH:mm"); }
}
This code does not work:
var MyClass = function() {
this.time = function() { return 4.5; }
this.time.formatted = function() { return format(this.time(), "HH:mm"); }
}
var m = new MyClass();
console.log(m.time.formatted())
Because the this inside .formatted points to m.time, not m. You should use:
var MyClass = function() {
this.time = function() { return 4.5; }
this.time.formatted = function() { return format(this(), "HH:mm"); }
}
or
var MyClass = function() {
var self = this;
this.time = function() { return 4.5; }
this.time.formatted = function() { return format(self.time(), "HH:mm"); }
}
Answering your actual question, make a helper function:
var callable(f, props) {
for(p in props) f[p] = props[p];
return f;
}
MyClass.prototype = {
time: callable(function() {
return 4.5;
}, {
formatted: function () { return format(this(), "HH:mm"); }
})
}

Categories