Dynamically add argument to function in javascript - javascript

I'm testing my app, I have a dependency injection system that works like this (I paste here a very simplified version)
test.start = function(callback) {
// do stuff;
load(callback);
}
function load(callback) {
var args = ...// read callback's arguments
// args = ['moduleA', 'moduleB'];
var injectedArgs = args.map(function(a) {
return require('./lib/' + a);
});
// call function with deps injected
callback.apply(null, injectedArgs);
}
// test.js
test.start(function(moduleA, moduleB) {
moduleA.functionA();
moduleB.functionB();
});
What I need to do is an async job before calling the callback and start the test, in this particular case, that would be
test.start = function(callback) {
// do stuff;
load(function(moduleA, moduleB, moduleC) {
moduleC.resetData(function() {
return callback(moduleA, moduleB);
})
});
}
I need to make this dynamic, for all the test that have different modules as their callback arguments.
Requirements are
I don't want to change test definitions
I must call load only once per test
So basically I need to create the middle function that add moduleC argument, run the resetData function and call the original callback.
I can build the dynamically extended argument list using
var fn = new Function(newArgumentList, /*function body*/) but I can't attach the correct function body (using a string) because I lose the original callback context.
UPDATE
The DI library is modularity and it reads the callback definition to grab dependency. So basically, given the callback function(foo, bar) { ... } I need to create a new function(foo, bar, db) { db.resetData(function() { return callback(foo, bar) } )}

If load, itself, is something you can change (e.g., not part of the test definitions), you'll be glad to know this is quite easy to do: You use Function#apply:
function load(callback) {
var origCallback;
if (/*flag saying you need to do this*/) {
origCallback = callback;
callback = function() {
/*...do your injected work here...*/
return origCallback.apply(this, arguments); // `arguments` looks like pseudo-code, but it isn't; it's an identifier created in the function's scope (for non-arrow functions)
};
}
var args = ...// read callback's arguments
// args = ['moduleA', 'moduleB'];
var injectedArgs = args.map(function(a) {
return require('./lib/' + a);
});
// call function with deps injected
callback.apply(null, injectedArgs);
}
You can even do it if you can't change load, provided you can update the load symbol to make it point at a new function:
var oldload = load;
load = function() {
/*...do your reset work here...*/
return oldload.apply(this, arguments);
};
If you're curious, yes, you can update the symbols created by function declarations (and yes, that's per spec, not "tricky"). E.g., this is perfectly valid:
function foo() {
console.log("I'm foo");
}
var oldFoo = foo;
foo = function() {
console.log("I'm the new foo");
return oldFoo.apply(this, arguments);
};
foo(); // "I'm the new foo", then "I'm foo"
Example:
function foo() {
snippet.log("I'm foo");
}
var oldFoo = foo;
foo = function() {
snippet.log("I'm the new foo");
return oldFoo.apply(this, arguments);
};
foo(); // "I'm the new foo", then "I'm foo"
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

I found out the solution at the end.
Since modularity supports angular-like injection like this
['modules/a', 'modules/b', function(moduleA, moduleB) {
// use modules here
}]
I could write my custom callback like this
var customCallback = function() {
var args = Array.prototype.slice.call(arguments);
var injectedDBModule = args.pop();
injectedDBModule.resetData(function() {
// call the original callback function
return originalCallback.apply(null, args);
}
}
var loadCallback = originalInjectedModules; // ['moduleA', 'moduleB']
loadCallback.push('db');
loadCallback.push(customCallback);
modularity.load(loadCallback);

Related

Problems with calling function inside function using `this`

window.onerror = function(e){alert(e)};
function main(){
this.work = [];
this.start_working = function() {
try{
if(this.work.length > 0){
var y = this.work.shift();
y.func(y.args);
}
}
catch(e){alert(e)};
};
this.add_work = function(f, a){
this.work.push({func:f, args:a});
};
this.foo = function(){
function footoo(){alert("bar");}
this.add_work(footoo);
};
this.foothree = function(){
this.add_work(this.foo);
};
this.start = function(){
setInterval(function(){this.start_working();}.bind(this), 1);
};
};
x = new main();
x.start();
x.foothree();
This is the watered down version of a function I am using elsewhere to run animations sequentially.
Expected behavior:
this.foothree is processed by the interval adding foo to the interval. this.foo is then processed adding footoo to the interval which is finally processed alerting "bar".
Problem:
when this.foothree is processed, an error is thrown:
TypeError: this.add_work is not a function.
Why don't I use something simpler:
Basically I need a function which allows me to compose a more complex animation made of simpler animations to the queue to be processed so I can reuse that animation. Foothree in this instance is just simulating a call which would add the real animation, footoo, to the queue to be processed. Footoo would be composed of simpler animations, foo, which would be executed sequentially.
this returns the [[ThisValue]] property of the EnvironmentRecord of the LexicalEnvironment of the ExecutionContext of the running function (see the spec).
Its value depends on how the function is called. If you call
this.foo = function(){
function footoo(){alert("bar");}
this.add_work(footoo);
};
in the function being declared there is no add_work method.
You should adopt var _self = this; pattern in order to point the correct calling context.
Basically the code should be rewritten as follows:
function main(){
var _self = this;
this.work = [];
this.start_working = function() {
try{
if(_self.work.length > 0){
var y = _self.work.shift();
y.func(y.args);
}
}
catch(e){alert(e)};
};
this.add_work = function(f, a){
_self.work.push({func:f, args:a});
};
this.foo = function(){
function footoo(){alert("bar");}
_self.add_work(footoo);
};
this.foothree = function(){
_self.add_work(_self.foo);
};
this.start = function(){
setInterval(function(){_self.start_working();}, 1);
};
};
Edit:
removed .bind(this) from original code.
This question has two components.
First it is a question about this in JavaScript aka the "target" or "receiver" of a function.
The target of a function in JavaScript depends on whether you are in strict mode, how the function was called and whether it was bound using bind.
Assuming strict mode (you should always put 'use strict'; at the top of your JavaScript):
foo(); // this inside foo will be undefined
a.foo(); // this inside foo will be a
a.foo.call(o); // this inside foo will be o
a.foo.apply(o); // this inside foo will be o
a.foo.bind(o)(); // this inside foo will be o
The second aspect to this question is what the author is attempting to do. I am pretty sure the complexity he is introducing to chain animations is unnecessary, and that he should be using requestAnimationFrame, but discussion of this would require another question.
Example:
function foo() {
document.write('foo', this, '<br/>');
bar();
}
function bar() {
document.write('bar', this, '<br/>');
}
foo();
document.write('------<br/>');
foo.call({});

How to get caller function class name

I tried some thing following, it fullfils 80% of the need though not enough to use.
// Different file
function A(){}
A.prototype.ao = function(){
// Here I want ot know the fucntion caller class name, for that I used
arguments.callee.caller.prototype; // It retuens B.bo {} (object)
}
// Different file
function B(){}
B.prototype.bo = function(){
var a = new A();
a.ao();
}
How to retrieve the class name from caller prototype, as it is of type object.
I would be more helpful, if we able to get the caller function context.
How to retrive the class name from caller prototype
You can't*, for a couple of reasons:
Functions don't have a name property. They will in ES6, but they don't yet. (You could assign a property to B with the name, though.)
Although you can get a reference to the function that's on B.prototype.bo, there's no link from there back to B. The linkage is one-way. (Not least because the same function could be on multiple objects.)
Note that using arguments.callee is strongly discouraged, and disallowed in strict mode, and using caller is especially discouraged. There's almost always a better way to do what you're trying to do.
* On some engines, you might be able to figure it out from the call stack, e.g.:
A.prototype.ao = function(){
try {
throw new Error();
}
catch (e) {
// Examine e.stack here
}
};
You'd be relying on platform-specific naming and such.
But again, there's almost certainly a better option than trying to know who's calling you.
Re your comment:
Here my requirement is to track an API function usage, in order to achieve it I am following this way...And further I can't change the existed framework.
You probably can but don't realize it, because JavaScript is that powerful. :-)
For instance: Once whatever framework creates B is loaded on the page, here's code that will wrap every function on B.prototype with a version that tells you it's running:
function wrapFunctions(name, proto) {
Object.keys(proto).forEach(function(key) {
var original = proto[key];
if (typeof original === "function") {
proto[key] = function() {
var rv;
starting(name, key); // <=== Your function to tracking the start of a call
rv = original.apply(this, arguments);
stopping(name, key); // <=== Your function tracking the end of the call
return rv;
};
}
});
}
wrapFunctions("B", B.prototype);
That's the beginning of "instrumentation." But note that there are proper libraries out there for this that have solved the edge cases and such.
Live Example:
// The framework
function B() {}
B.prototype.f1 = function() {
snippet.log("Original functionality for f1");
};
B.prototype.f2 = function() {
snippet.log("Original functionality for f2");
};
B.prototype.f3 = function() {
snippet.log("Original functionality for f3 -- calling f2");
this.f2();
snippet.log("Original functionality for f3 -- done calling f2");
};
// Let's use f1 and f2 before we wrap them
snippet.log("Before wrapping:");
var b1 = new B();
b1.f1();
b1.f2();
b1.f3();
// Now your code runs and wraps them
wrapFunctions("B", B.prototype);
// Now let's use f1 and f2 again
snippet.log("After wrapping:");
var b2 = new B();
b2.f1();
b2.f2();
b1.f3();
// Our function to track that a call started
function starting(ctor, name) {
snippet.log(ctor + "#" + name + ": Started");
}
// Our function to track that a call stopped
function stopping(ctor, name) {
snippet.log(ctor + "#" + name + ": Stopped");
}
// Our function to wrap things
function wrapFunctions(name, proto) {
Object.keys(proto).forEach(function(key) {
var original = proto[key];
if (typeof original === "function") {
proto[key] = function() {
var rv;
starting(name, key); // <=== Your function to tracking the start of a call
rv = original.apply(this, arguments);
stopping(name, key); // <=== Your function tracking the end of the call
return rv;
};
}
});
}
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
You can include a method in the object which returns its type. Another option is to use instanceof and check for all possible types.
function A() {
this.getType = function () {
return "A";
}
}
A.prototype.ao = function() {
// Here I want ot know the fucntion caller class name, for that I used
var type = this.getType();
args.callee.caller.prototype; // It retuens B.bo {} (object)
}
function B(){
this.getType = function () {
return "B";
}
}
B.prototype.bo = function(){
var a = new A();
a.ao.apply(this);
}
Here you will also have to redefine getType in all of your inherited types and return the correct type. You also need to invoke the desired method with apply(this) to provide the context of the current caller.

Call method if return value is not used

Here is a sample code that I want to achieve
function myObj(){
this.method1 = function() {
console.log('method 1 is called');
}
// if method1 is not called ...
this.default = function() {
console.log('default method is called');
}
return this;
}
myObj(); // call default
myObj().method1(); // call method1
In this code I want to be able to detect if the myObj() return object (which has a method1 method) is being used or not.
If that's the case (if we chain myObj() to something else) then execute the last chained method. If not then execute a default method in myObj();
One approach that I had was to return a function from myObj() and act like :
myObj()();
myObj().method1()();
I can also pass the method(s) to the base function and chain it inside the object :
myObj();
myObj(method1);
But maybe there is another way to do such thing, do you have an idea ?
Thanks,
You can't detect it within myObj without doing something like your example where you call the result, like this:
function myObj(){
var rv = function() {
snippet.log("default method called");
};
rv.method1 = function() {
snippet.log('method 1 is called');
};
return rv;
}
myObj()(); // call default, note the extra ()
myObj().method1(); // call method1 [*no* extra ()]
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
In a comment I said requiring the extra () was asking for trouble because it would be so easy to forget, but of course, if myObj itself doesn't do anything but return a function, then if you forget the () you won't see the default functionality and presumably will realize you've forgotten the ().
In a comment elsewhere you said you might want to do chaining. You can do that with the above, just add "return rv" to the end of the functions:
function myObj(){
var rv = function() {
snippet.log("default method called");
return rv;
};
rv.method1 = function() {
snippet.log('method 1 is called');
return rv;
};
return rv;
}
myObj()(); // call default, note the extra ()
myObj().method1(); // call method1 [*no* extra ()]
myObj()().method1()(); // call default, then method1, then default
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
I'm sure you've already ruled this out, but just for completeness: The usual way to do this would be for the "default" to be explicit, e.g.:
function myObj(){
return {
_: function() {
snippet.log("default method called");
},
method1: function() {
snippet.log('method 1 is called');
}
};
}
myObj()._(); // call default
myObj().method1(); // call method1
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
And then of course you can use the prototype chain and all the other standard object goodness.
Detecting if the return value of a function has its methods called later is not something that you can reasonably do. However, your plan of just passing the second function into the first is a tried-and-true pattern. You could do something like this:
function myObj(callback) {
function defaultFunc() {/* code */}
//other code, properties, etc
//check if the user wants to chain functions
if(callback) {
callback();
}
//call the default function if there is nothing else to execute
else {
defaultFunc();
}
}
Usage:
myObj(method1); // Where method1 is a function defined somewhere
If you don't want to pass a whole function into your object but only want to execute one of myObj's properties, you could just pass the name of the function too.
function myObj(methodName) {
this.defaultFunc = function() {/* code */}
this.myMethod = function() {/* code */}
//other code, properties, etc
//check if the user wants to chain functions
if(methodName && this[methodName]) {
this[methodName]();
}
//call the default function if there is nothing else to execute
else {
this.defaultFunc();
}
}
Usage:
new myObj("method1"); // Note it's a string
I think this will be helpful:
var myObj = function(callDefault){
if(callDefault){
// DEFAULT METHOD GOES HERE
console.log('default method is called')
// DO SOMETHING
}
return {
method1: function(){
console.log('method 1 is called');
// DO SOMETHING
},
method2: function(){
console.log('method 2 is called');
// DO SOMETHING
}
}
}
myObj(true) // calls default function and returns list of other functions
myObj().method1() // Calls Method 1 Only
myObj().method2() // Calls Method 2 Only
myObj(true).method1() // Calls Default then Method 1
myObj(true).method2() // Calls Default then Method 2
Just for the example, this is not the way to do :
function myObj(){
var isCalled = false;
this.method1 = function() {
isCalled = true;
console.log('method 1 is called');
}
this.default = function() {
if(isCalled) return;
console.log('default method is called');
}
setTimeout(this.default, 1000); // default time
return this;
}
myObj(); // after 1 s default is called
myObj().method1(); // method1 is called right away and default is never called
If I understand you correctly, you need a constructor function that takes one argument as input and creates an object with a method attached to it. If the input argument was a valid call-back function then call it, otherwise call a default function instead.
function myObj(callback) {
this.method = function() {
if(typeof callback == 'function'){
callback();
console.log('call-back is called');
} else {
// default function
console.log('default method is called');
}
}
}
Usage:
(new myObj()).method(); // call default
(new myObj(somefunction)).method(); // call 'somefunction'

chain functions directly to newly created object instance in Javascript

In my ongoing saga to understand more about Object Oriented Javascript - I came across a question about creating a class to respond to the following API:
var foo = new bar().delay(750).start().then(onComplete);
var bar = function() {
this.delay(function(per) {
//...
};
}
Can someone with more experience than me please describe how to create class that would respond to this? I have never seen chaining like this and can't find any information online :(
This chaining is accomplished by returning this in your functions :
this.delay = function(per) {
//...
return this;
};
If you want to stick to first line code, then your constructor should be named bar :
var bar = function() {
this.delay = function(per) {
//...
return this;
};
this.start = function() {
...
return this;
};
}
See demonstration (open the console)
The secret to method chaining is to return this from each method that you want to be able to chain with. That allows the next method to be this.method() automatically. Your definition of the bar object would look something like this shell:
function bar() {
// bar initialization code here
}
bar.prototype = {
delay: function(amt) {
// delay code here
return(this);
},
start: function() {
// start code here
return(this);
},
then: function(fn) {
// then code here
fn();
return(this);
}
};
var foo = new bar().delay(750).start().then(onComplete);
In your example, new bar() is executed and it returns a pointer to the new bar object.
Using that new object pointer, the .delay(750) method is called on that object. That method then also returns the object so the .start() method is called on the return value from .delay(750) which is still the same object and so on...

Getting a 'this' reference to a 2nd level prototype function

I'm fairly certain this isn't possible, but wanted to see if anyone had some ingenious ideas as to how to make it possible.
I want the following code to work:
var x = new foo();
x.a.getThis() === x; // true
In other words, I want x.a.getThis to have a reference to this being x in this case. Make sense?
In order to get this to work one level deep is simple:
function foo(){}
foo.prototype.getThis = function(){ return this; }
var x = new foo();
x.getThis() === x; // true
One thing, I want this to work as a prototype, no "cheating" by manually binding to this:
function foo(){
this.a = {
getThis : (function(){ return this; }).bind(this)
};
}
Although the above is a perfect functional example of what I'm trying to achieve, I just don't want all the extra functions for each instance :)
FYI, the actual use case here is that I'm creating classes to represent Cassandra objects in node and I want to be able to reference a super-column --> column-family --> column via foo.a.b and keep a reference to foo in the deep function.
You can't do this without a forced bind of some kind. You say you don't want to "cheat" but this breaks the standard rules about what this is, so you have to cheat. But JS lets you cheat, so it's all good.
BTW, for what it's worth coffee script makes this so trivial.
foo = ->
#a = getThis: => this
The fat arrow => preserves the context of this for from the scope it was called in. This allows you to easily forward the context to another level.
That code gets compiled to this JS:
var foo;
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
foo = function() {
return this.a = {
getThis: __bind(function() {
return this;
}, this)
};
};
Which basically just does what you say you do not want to do.
Or if the value doesn't have to this specifically, you can set the "owner" in the child object.
var A = function(owner) {
this.owner = owner;
};
A.prototype.getThis = function() {
return this.owner;
};
var Foo = function() {
this.a = new A(this);
};
var foo = new Foo();
if (foo.a.getThis() === foo) {
alert('Happy dance');
} else {
window.location = 'https://commons.lbl.gov/download/attachments/73468687/sadpanda.png';
}
http://jsfiddle.net/4GQPa/
And the coffee script version of that because I am a passionate and unreasonable zealot for it:
class A
constructor: (#owner) ->
getThis: -> #owner
class Foo
constructor: -> #a = new A(this)
foo = new Foo()
if foo.a.getThis() is foo
alert 'Happy Dance'
else
window.location = 'https://commons.lbl.gov/download/attachments/73468687/sadpanda.png'
Impossible to do reliably without binding the value at the start since the value of a function's this is set by the call. You can't know beforehand how it will be called, or which functions need a special or restricted call to "preserve" the this -> this relationship.
The function or caller's this may be any object, there may not be a this -> this at all. Consider:
var x = {
a : {
b: function() {return this;}
}
}
When you call x.a.b(), then b's this is a. But if you do:
var c = x.a.b;
c(); // *this* is the global object
or
x.a.b.call(someOtherObject);
What is the value of this -> this in these cases?
Answering my own question because someone else may find it useful. Not sure if I'll end up going with this or Squeegy's solution. The functions are only ever defined once and then the containing object is cloned and has parent = this injected into it:
function foo(){
var self = this, nest = this.__nestedObjects__ || [];
nest.forEach(function(prop){
self[prop] = extend({ parent : self }, self[prop]);
});
}
// bound like this so that they're immutable
Object.defineProperties(foo.prototype, {
bar : {
enumerable : true,
value : {
foobar : function(){
return this.parent;
},
foo : function(){},
bar : function(){}
}
},
__nestedObjects__ : { value : ['bar'] }
});
var fooInst = new foo();
console.log(fooInst.bar.foobar() == fooInst);
or based on Squeegy's solution:
function foo(){
for(var cls in this.__inherit__){
if(!this.__inherit__.hasOwnProperty(cls)){ continue; }
this[cls] = new (this.__inherit__[cls])(this);
}
}
var clsA;
// bound like this so that they're immutable
Object.defineProperties(foo.prototype, {
__inherit__ : { value : {
bar : clsA = function(parent){
Object.defineProperty(this, '__parent__', { value : parent });
}
}
}
});
clsA.prototype = {
foobar : function(){
return this.__parent__;
}
};
var fooInst = new foo();
console.log(fooInst.bar.foobar() == fooInst);

Categories