So far I haven't been able to grok any Delegate function tutorials out there for Javascript. Even less so the ones with parameters.
Hopefully my current problem will provide a good example. (XXXX() is a function I am passing to Fee())
The way I have it now, my "delegate", (XXXX()) executes as soon as Fee() is called, not when I want it to be called (somewhere inside of Fee())
line of code that calls function:
Fee(prod, item, "usage", i, y, XXXX(prod, y));
Function:
function Fee(prod, item, name, i, y, func) {
var open = false;
var prefix = "#" + prod + name;
$(prefix + y).click(function () {
var feeBoxName = prefix + "FeeBox" + y;
if (open == false) {
FeeOpen(prefix, y);
func; //delegate is called here
AddFeeButton(feeBoxName, "addFeeBtn2");
open = true;
} else {
FeeClosed(prefix, y);
open = false;
}
});
}
Delegate function:
function XXXX(prod, y) {
var deducedFeeBoxName = "#" + prod + "usageFeeBox" + y;
alert(deducedFeeBoxName); //at present, this is called immediately when Fee is executed
UsageFeeBoxHeader(deducedFeeBoxName);
UsageFeeBoxData(deducedFeeBoxName, prod, y);
}
Comments?
You want:
Fee(prod, item, "usage", i, y, function() { XXXX(prod, y); });
It's usually not called a "delegate" in Javascript. I believe that's a term mostly used in the Microsoft part of the world. We just call it a lambda or anonymous function.
You also have a bug in the main (Fee) function. Change this line:
func(); //delegate is called here
If your function is called XXX, then if you use this syntax: XXX(), you are invoking your function. To pass it in as a delegate, you simply pass in XXX:
Fee(prod, item, "usage", i, y, XXX);
The Fee method will be responsible for invoking it and determining which parameters are passed into the method.
Related
I know many of you already used JavaScript UI widget plugins, etc... that offers callback functions. For instance we have Object x and it has a function, let say .doThisAfterAnEvent(). And according to the official documentation of Object x, that function accepts a single parameter of type function() with one argument, let say _args.
To visualize, here is the example:
var handler = function(_args) {
// Do something.
}
var x = $("#element-to-widget-ify").transform()
x.doThisAfterAnEvent(handler)
My question is, how can I modify the method .doThisAfterAnEvent() to accept a function with two or more parameters instead of one? In this case, I need to pass a second extra value to the handler function.
Edit:
var widgets = {
"widget-at-the-nav": $("#nav-widget").transform(),
"widget-at-the-footer": $("#nav-footer").transform(),
"widget-at-the-search": $("#nav-search").transform(),
length: 3
}
var handler = function(_args, _option) {
console.log("key in: " + _option
// Other processes...
}
for(key in widgets) {
console.log("key outer: " + key)
widget[key].doThisAfterAnEvent(function(json) {
console.log("key out: " + key)
handler(json, key)
})
}
This is my attempt. But it prints like this:
key outer: widget-at-the-nav
key outer: widget-at-the-footer
key outer: widget-at-the-search
key out: widget-at-the-nav
key in: widget-at-the-nav
key out: widget-at-the-nav
key in: widget-at-the-nav
key out: widget-at-the-nav
key in: widget-at-the-nav
And I forgot to tell you guys that the function .doThisAfterAnEvent() (not the handler() function) has an AJAX call inside.
This question is a mess, so I'm only going to touch on the most recent edit, and the code it contains.
Your approach with masking the handler with an anonymous function is pretty much correct, it's just that your loop is messing up your lexical scope. The AJAX bit is a very important detail, because any AJAX calls are most likely going to operate long after you've looped, which means those callback functions will all reference the same final value of key.
You need to create a new scope where the key is 'locked in', so that the references are correct.
function Con () {}
Con.prototype.doThisAfterAnEvent = function (fn) {
// Fake some AJAX programming
window.setTimeout(function () {
fn.call(this);
}, 1500);
};
$.fn.transform = function () {
return new Con();
};
var widgets = {
"widget-at-the-nav": $("#nav-widget").transform(),
"widget-at-the-footer": $("#nav-footer").transform(),
"widget-at-the-search": $("#nav-search").transform()
};
var handler = function(_args, _option) {
console.log("key in: " + _option);
// Other processes...
};
for (var key in widgets) {
console.log("key outer: " + key);
(function (key) {
// Use an IIFE to establish a new lexical scope
widgets[key].doThisAfterAnEvent(function(json) {
console.log("key out: " + key);
handler(json, key);
});
}(key));
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
In ES6, we'd use let.
If you ask that, I guess you mean at the moment you call doThisAfterAnEvent, you already know one parameter over two for your handler.
In this case, the solution is too wrap your handler with two parameter in a anonymous function that only take one parameter and then call back your handler :
x.doThisAfterAnEvent(function(_arg) { handler(myKnownArg, _arg) });
I would like to know the best way to detect when a method or function is directly called through the console. As far as I currently understand, it's not possible to directly detect it on identical function calls, but using the .call() and .apply() methods of a function I can pass additional data through the this object.
Given the following code structure:
(function(){
var Player = {money: 0};
window.giveMoney = function(amount){
if (this.legit !== true)
throw new Error("Don't try to cheat!");
Player.money += amount;
}
})();
I could call the function using
window.giveMoney.call({legit: true}, 300);
in my actual code to tell a direct call from the console and my own code apart, but this is obviously not fool-proof, since the same code can also be executed from the console to achieve the desired effect.
I would want a way to be able to call the function from both places and then tell the locations of the call apart. If there's no way to do that, what's the best way to try and prevent the execution anyway? Is it best to just not expose any methods at all, and keep everything inside a single closed-off anonymous function?
To prevent global access make sure your code is in a closure. If you want to expose an API you can do so using the module pattern.
Closure
(function() {
var Game = {};
Game.giveMoney = function(money) {
console.log('Gave money (' + money + ')');
};
})();
Wrap all your private code in an IIFE (Immediately Invoked Function Expression) which will lock it up into a closure.
Module
Then expose only custom functions back out of the closure so you can use them on the console (with supervision of course).
window.Game = (function() {
var player = {
money: 500;
};
player.giveMoney = function(money) {
console.log('Gave money (' + money + ')');
player.money += money;
};
player.takeMoney = function(money) {
console.log('Took money (' + money + ')');
player.money -= money;
};
return {
giveMoney: function(money) {
console.error('Don\'t Cheat! A fine was charged.');
player.takeMoney(Math.floor(player.money / 0.05));
}
};
})();
window.Game.giveMoney(200);
You can spool all function calls through a central access point with a boolean variable, that can serve as a indicator whether the call is from a console or not....
var maths = {
add: function(p1,p2)
{
console.log(p1,p2);
}
}
var invoker = {
invoke: function(fu,isconsole)
{
if(isconsole)
{
console.log("Called from console");
}
//invokes the function with all parameters intact
fu;
}
}
//Call without console
invoker.invoke(maths.add(2,3));
//Call with console
invoker.invoke(maths.add(2,3),true);
Hope it helps!!!
You can use the monitor() command in the console to monitor when a function is called. https://developer.chrome.com/devtools/docs/commandline-api#monitorfunction
Just run monitor(functionName); and whenever the function is called it will output a message in the console.
Here is a simplified snippet from some code I wrote for managing tablet gestures on canvas elements
first a function that accepts an element and a dictionary of callbacks and register the events plus adding other features like 'hold' gestures:
function registerStageGestures(stage, callbacks, recieverArg) {
stage.inhold = false;
stage.timer = null;
var touchduration = 1000;
var reciever = recieverArg || window;
stage.onLongTouch = function(e) {
if (stage.timer) clearTimeout(stage.timer);
stage.inhold = true;
if (callbacks.touchholdstart) callbacks.touchholdstart.call(reciever, e);
};
stage.getContent().addEventListener('touchstart', function(e) {
e.preventDefault();
calcTouchEventData(e);
stage.timer = setTimeout(function() {
stage.onLongTouch(e);
}, touchduration);
if (callbacks.touchstart) callbacks.touchholdstart.call(reciever, e);
});
stage.getContent().addEventListener('touchmove', function(e) {
e.preventDefault();
if (stage.timer) clearTimeout(stage.timer);
if (stage.inhold) {
if (callbacks.touchholdmove) callbacks.touchholdmove.call(reciever, e);
} else {
if (callbacks.touchmove) callbacks.touchmove.call(reciever, e);
}
});
stage.getContent().addEventListener('touchend', function(e) {
e.preventDefault();
if (stage.timer) clearTimeout(stage.timer);
if (stage.inhold) {
if (callbacks.touchholdend) callbacks.touchholdend.call(reciever, e);
} else {
if (callbacks.touchend) callbacks.touchend.call(reciever, e);
}
stage.inhold = false;
});
}
later I call registerStageGestures on a few elements (represented by 'View' objects) in the same page. Something like:
function View() {
var self=this;
..
function InitView() {
...
registerStageGestures(kineticStage, {
touchstart: function(e) {
// do something
},
touchmove: function(e) {
// do something
},
touchendunction(e) {
// do something
},
touchholdstart: function(e) {
// do something
},
touchholdmove: function(e) {
// do something
},
touchholdend: function(e) {
// do something
},
}, self);
Everything works fine, however I'm left wondering about two things in the implementation of registerStageGestures:
First, is it necessary to make inhold, timer and onLongTouch members of the stage ? or will closures make everything works well if they are local vars in registerStageGestures ?
Second, is it necessary to call the callbacks with '.call(receiver,' syntax ? I'm doing this to make sure the callback code will run in the context of the View but I'm not sure if it's needed ?
any input is much appreciated
Thanks!
First, is it necessary to make inhold, timer and onLongTouch members
of the stage ? or will closures make everything works well if they are
local vars in registerStageGestures ?
As far as registerStageGestures() is concerned, var inhold, var timer and function onLongTouch(e) {...}. would suffice. The mechanism by which an inner function has automatic access to its outer function's members is known as "closure". You would only need to set stage.inhold, stage.timer and stage.onLongTouch if some other piece of code needs access to these settings as properties of stage.
Second, is it necessary to call the callbacks with '.call(receiver,'
syntax ? I'm doing this to make sure the callback code will run in the
context of the View but I'm not sure if it's needed ?
Possibly, depending on how those callbacks are written. .call() and .apply() are sometimes used when calling functions that use this internally. In both cases, the first parameter passed defines the object to be interpreted as this. Thus, javascript gives you the means of defining general purpose methods with no a priori assumption about the object to which those methods will apply when called. Similarly, you can call a method of an object in such a way that it acts on another object.
EDIT:
For completeness, please note that even in the absence of this in a function, .apply() can be very useful as it allows multiple parameters to be specified as elements of a single array, eg the ubiquitous jQuery.when.apply(null, arrayOfPromises)...
There are some simple answers, here.
First, closure:
Closure basically says that whatever is defined inside of a function, has access to the rest of that function's contents.
And all of those contents are guaranteed to stay alive (out of the trash), until there are no more objects left, which ere created inside.
A simple test:
var testClosure = function () {
var name = "Bob",
recallName = function () { return name; };
return { getName : recallName };
};
var test = testClosure();
console.log(test.getName()); // Bob
So anything that was created inside can be accessed by any function which was also created inside (or created inside of a function created in a function[, ...], inside).
var closure_2x = function () {
var name = "Bob",
innerScope = function () {
console.log(name);
return function () {
console.log("Still " + name);
}
};
return innerScope;
};
var inner_func = closure_2x();
var even_deeper = inner_func(); // "Bob"
even_deeper(); // "Still Bob"
This applies not only to variables/objects/functions created inside, but also to function arguments passed inside.
The arguments have no access to the inner-workings(unless passed to methods/callbacks), but the inner-workings will remember the arguments.
So as long as your functions are being created in the same scope as your values (or a child-scope), there's access.
.call is trickier.
You know what it does (replaces this inside of the function with the object you pass it)...
...but why and when, in this case are harder.
var Person = function (name, age) {
this.age = age;
this.getAge = function () {
return this.age;
};
};
var bob = new Person("Bob", 32);
This looks pretty normal.
Honestly, this could look a lot like Java or C# with a couple of tweaks.
bob.getAge(); // 32
Works like Java or C#, too.
doSomething.then(bob.getAge);
? Buh ?
We've now passed Bob's method into a function, as a function, all by itself.
var doug = { age : 28 };
doug.getAge = bob.getAge;
Now we've given doug a reference to directly use bobs methid -- not a copy, but a pointer to the actual method.
doug.getAge(); // 28
Well, that's odd.
What about what came out of passing it in as a callback?
var test = bob.getAge;
test(); // undefined
The reason for this, is, as you said, about context...
But the specific reason is because this inside of a function in JS isn't pre-compiled, or stored...
this is worked out on the fly, every time the function is called.
If you call
obj.method();
this === obj;
If you call
a.b.c.d();
this === a.b.c;
If you call
var test = bob.getAge;
test();
...?
this is equal to window.
In "strict mode" this doesn't happen (you get errors really quickly).
test.call(bob); //32
Balance restored!
Mostly...
There are still a few catches.
var outerScope = function () {
console.log(this.age);
var inner = function () {
console.log("Still " + this.age);
};
inner();
};
outerScope.call(bob);
// "32"
// "Still undefined"
This makes sense, when you think about it...
We know that if a function figures out this at the moment it's called -- scope has nothing to do with it...
...and we didn't add inner to an object...
this.inner = inner;
this.inner();
would have worked just fine (but now you just messed with an external object)...
So inner saw this as window.
The solution would either be to use .call, or .apply, or to use function-scoping and/or closure
var person = this,
inner = function () { console.log(person.age); };
The rabbit hole goes deeper, but my phone is dying...
var BigObject = (function() {
function deepCalculate(a, b, c) {
return a + b + c;
}
function calculate(x) {
deepCalculate(x, x, x);
}
return {
calculate: calculate,
api: {
deepCalculate: deepCalculate
}
}
})();
This is basic self executing function with private function I keep in api.
The problem I have is that now I can't overwrite deepCalculate from the outside of the function.
How is that a problem? I use Jasmine and want to test if function was called. For example:
spyOn(BigObject, 'calculate').andCallThrough();
expect(BigObject.api.deepCalculate).toHaveBeenCalled();
fails. However as I debug, I am sure that Jasmine binds BigObject.api.deepCalculate as a spy, however from the inside calculate still calls original deepCalculate function and not the spy.
I would like to know how can I overwrite the function and not just a reference for it.
The simple answer would be:
(function ()
{
var overWriteMe = function(foo)
{
return foo++;
},
overWrite = function(newFunc)
{
for (var p io returnVal)
{
if (returnVal[p] === overWriteMe)
{//update references
returnVal[p] = newFunc;
break;
}
}
overWriteMe = newFunc;//overwrite closure reference
},
returnVal = {
overWrite: overWrite,
myFunc: overWriteMe
};
}());
Though I must say that, I'd seriously think about alternative ways to acchieve whatever it is you're trying to do. A closure, IMO, should be treated as a whole. Replacing parts of it willy-nilly will soon prove to be a nightmare: you don't know what the closure function will be at any given point in time, where it was changed, what the previous state was, and why it was changed.
A temporary sollution might just be this:
var foo = (function()
{
var calc = function(x, callback)
{
callback = callback || defaultCall;
return callback.apply(this, [x]);
},
defaultCall(a)
{
return a*a+1;
},
return {calc: calc};
}());
foo(2);//returns 5
foo(2,function(x){ return --x;});//returns 1
foo(2);//returns 5 again
IMO, this is a lot safer, as it allows you to choose a different "internal" function to be used once, without changing the core behaviour of the code.
When you call a function in JavaScript and you miss to pass some parameter, nothing happens.
This makes the code harder to debug, so I would like to change that behavior.
I've seen
How best to determine if an argument is not sent to the JavaScript function
but I want a solution with a constant number of typed lines of code; not typing extra code for each function.
I've thought about automatically prefixing the code of all functions with that code, by modifying the constructor of the ("first-class") Function object.
Inspired by
Changing constructor in JavaScript
I've first tested whether I can change the constructor of the Function object, like this:
function Function2 () {
this.color = "white";
}
Function.prototype = new Function2();
f = new Function();
alert(f.color);
But it alerts "undefined" instead of "white", so it is not working, so I've don't further explored this technique.
Do you know any solution for this problem at any level? Hacking the guts of JavaScript would be OK but any other practical tip on how to find missing arguments would be OK as well.
If a function of yours requires certain arguments to be passed, you should check for those arguments specifically as part of the validation of the function.
Extending the Function object is not the best idea because many libraries rely on the behavior of defaulting arguments that are not passed (such as jQuery not passing anything to it's scoped undefined variable).
Two approaches I tend to use:
1) an argument is required for the function to work
var foo = function (requiredParam) {
if (typeof requiredParam === 'undefined') {
throw new Error('You must pass requiredParam to function Foo!');
}
// solve world hunger here
};
2) an argument not passed but can be defaulted to something (uses jQuery)
var foo = function (argumentObject) {
argumentObject = $.extend({
someArgument1: 'defaultValue1',
someArgument2: 'defaultValue2'
}, argumentObject || {});
// save the world from alien invaders here
};
As others have said, there are many reasons not to do this, but I know of a couple of ways, so I'll tell you how! For science!
This is the first, stolen from Gaby, give him an upvote! Here's a rough overview of how it works:
//example function
function thing(a, b, c) {
}
var functionPool = {} // create a variable to hold the original versions of the functions
for( var func in window ) // scan all items in window scope
{
if (typeof(window[func]) === 'function') // if item is a function
{
functionPool[func] = window[func]; // store the original to our global pool
(function(){ // create an closure to maintain function name
var functionName = func;
window[functionName] = function(){ // overwrite the function with our own version
var args = [].splice.call(arguments,0); // convert arguments to array
// do the logging before callling the method
if(functionPool[functionName].length > args.length)
throw "Not enough arguments for function " + functionName + " expected " + functionPool[functionName].length + " got " + args.length;
// call the original method but in the window scope, and return the results
return functionPool[functionName].apply(window, args );
// additional logging could take place here if we stored the return value ..
}
})();
}
}
thing(1,2 ,3); //fine
thing(1,2); //throws error
The second way:
Now there is another way to do this that I can't remember the details exactly, basically you overrride Function.prototype.call. But as it says in this question, this involves an infinite loop. So you need an untainted Function object to call, this is done by a trick of turning the variables into a string and then using eval to call the function in an untainted context! There's a really great snippet out the showing you how from the early days of the web, but alas I can't find it at the moment. There's a hack that's required to pass the variables properly and I think you may actually lose context, so it's pretty fragile.
Still, as stated, don't try and force javascript to do something against its nature, either trust your fellow programmers or supply defaults, as per all the other answers.
You can imitate something like Python’s decorators. This does require extra typing per function, though not extra lines.
function force(inner) {
return function() {
if (arguments.length === inner.length) {
return inner.apply(this, arguments);
} else {
throw "expected " + inner.length +
" arguments, got " + arguments.length;
}
}
}
var myFunc = force(function(foo, bar, baz) {
// ...
});
In general this sounds like a bad idea, because you’re basically messing with the language. Do you really forget to pass arguments that often?
You could use the decorator pattern. The following decorator allows you to specify minimum and maximum number of arguments that need to be passed and an optional error handler.
/* Wrap the function *f*, so that *error_callback* is called when the number
of passed arguments is not with range *nmin* to *nmax*. *error_callback*
may be ommited to make the wrapper just throw an error message.
The wrapped function is returned. */
function require_arguments(f, nmin, nmax, error_callback) {
if (!error_callback) {
error_callback = function(n, nmin, nmax) {
throw 'Expected arguments from ' + nmin + ' to ' + nmax + ' (' +
n + ' passed).';
}
}
function wrapper() {
var n_args = arguments.length;
console.log(n_args, nmin, nmax);
console.log((nmin <= 0) && (0 <= nmax));
if ((nmin <= n_args) && (n_args <= nmax)) {
return f.apply(this, arguments);
}
return error_callback(n_args, nmin, nmax);
}
for (e in f) {
wrapper[e] = f[e];
}
return wrapper;
}
var foo = require_arguments(function(a, b, c) {
/* .. */
}, 1, 3);
foo(1);
foo(1, 2);
foo(1, 2, 3);
foo(1, 2, 3, 4); // uncaught exception: Expected arguments from 1 to 3 (4 passed).
foo(); // uncaught exception: Expected arguments from 1 to 3 (0 passed).