What's the use of passing function expression variables as parameters? - javascript

I am a beginning JS programmer working through codeschool's 3rd JS course. One of their modules introduces the concept of passing function expression variables as parameters for other functions. However, I need some help understanding why this method is better in some cases than in others. For example, the following code is for a conditional alert that is supposed to recognize whether the user is a new user and throw a customized greeting when the user logs out of the system.
This is what codeschool advocates:
var greeting;
var newCustomer;
//Some code sets the variable newCustomer to true or false
if( newCustomer ){
greeting = function () {
alert("Thanks for visiting the Badlands!\n" +
"We hope your stay is...better than most.");
};
} else {
greeting = function () {
alert("Welcome back to the Badlands!\n" +
"Guess they aren't so bad huh?");
};
}
closeTerminal( greeting );
function closeTerminal( message ){ message();}
But why is that better than the following?
var greeting;
var newCustomer;
//Some code sets the variable newCustomer to true or false
closeTerminal();
function closeTerminal(){
if( newCustomer ) {
alert("Thanks for visiting the Badlands!\n" +
"We hope your stay is...better than most.");
} else {
alert("Welcome back to the Badlands!\n" +
"Guess they aren't so bad huh?");
}
}
Which of these code blocks (or any other code) would a good developer use to achieve the desired result? Is there an advantage to storing an entire function in a variable over just using a single if . . . else statement to evaluate newCustomer and return the desired greeting?

In your case, it is not inherently better.
But there are cases where it isn't this simple. Assume that you cannot modify the closeTerminal function, but its developer still wants you to execute arbitrary functionality from deep with his logic? That's where you use a callback function. Passing function expressions for them is only natural, but not strictly required. Have a look at purpose of callbacks in javascript maybe.
Another usecase for callbacks are asynchronous functions, you might encounter them later.
A better example might be
function closeTerminal(getMessage) {
var isNewCustomer = !Math.round(Math.random()); // complicated, local logic
var message = getMessage(isNewCustomer);
alert(message); // print to the closing terminal
// (which is local to this function as well)
}
You could invoke it with
closeTerminal(function greeting(newCustomer) {
// passing a custom function to determine the appropriate message
if (newCustomer)
return "Thanks for visiting the Badlands!\nWe hope your stay is...better than most.";
else
return "Welcome back to the Badlands!\nGuess they aren't so bad huh?";
});

Here's an example of their use:
function load_home() {
var url = "http://localhost/inner_load/page_test.html";
var method = "GET";
var postData = " ";
var async = true;
var request = new XMLHttpRequest();
/* Have a close look at this */
request.onload = function () {
var data = request.responseText;
Contenido.innerHTML=request.responseText;
}
request.open(method, url, async);
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
request.send(postData);
}
As you can see, I can specify a function that defines an action that will be performed when the server returns a result. Another example would be:
function add(a, b) {
return a+b;
}
function mult(a, b) {
return a*b;
}
function calculate(func, a, b) {
return func(a, b);
}
In this case I can choose what to do with the values passed as a and b by passing a function as a parameter, if I pass add, the two numbers will be added, if I pass mult, they'd be multiplied.
calculate(add, 10, 5);
Will return 15. Where:
calculate(mult, 10, 5);
Would return 50.
This would save you a lot of trouble if you are doing, say, a calculator. Instead of using an if … else block and some var storing some integer numbers or strings to define the operations you want to perform, you could just call the function giving the operation you'd want to perform.

The concept of scalability and reusability. With your code it definitely works. For now. Any change requested from client would require you to modify a hell lot of code. While maintaining such granularity with functions, allows you to write code that works and works well.
I myself haven't gone through any codeschool tutorials but you might find Functions chapter in eloquent javascript interesting. Here is a link you can use.

In your version of the solution, you will always greet the user with only alert box. The version in the tutorial gives the caller of closeTerminal method the flexibilty to pass any method which can contain any logic. i.e show message in alert or in a new jquery ui dialog or bootstrap dialog or a completely different logic.
Please see the following code to understand how we can reuse your logic.
HTML
<div id="myDiv"></div>
Javascript
var greeting;
var newCustomer;
//Some code sets the variable newCustomer to true or false
if( newCustomer ){
greeting = function () {
alert("Thanks for visiting the Badlands!\n" +
"We hope your stay is...better than most.");
};
}else {
greeting = function () {
alert("Welcome back to the Badlands!\n" +
"Guess they aren't so bad huh?");
};
}
function closeTerminal( message ){ message();}
function divGreeting(){
document.getElementById('myDiv').innerHTML = "Thanks for visiting the Badlands!\n" +
"We hope your stay is...better than most."
}
closeTerminal( greeting );
closeTerminal( divGreeting );
Working sample - http://jsfiddle.net/7P2Ct/

Related

Best way to detect when a function is called from the console

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.

Advanced Javascript: The ALT way to do Pub/Priv in JS - is a mystery

Eric Miraglia of Yahoo/Google presents a very clean looking way to implement information hiding in JavaScript:
http://www.yuiblog.com/blog/2007/06/12/module-pattern/
Please note some experiments here:
http://jsfiddle.net/TvsW6/5/
My question is, why can I access the seemingly "public" variable "this.setting2" (and of course not _setting1) YET I cannot access the function "this.logSetting_priv" although it is in the same scope as this.setting2 (isn't it!?!?!?) Does any one know why?
Also, with the use of the return object for the public methods, I can't seem to add a function as I might normally with "LogSystem.prototype.publicFunc1." Why is that?
Mystery of the ages . . .
Pls checkout my JSFiddle but the JS is also below:
function LogSystem() {
//default
var _divId = "log";
var _setting1 = "default stuff";
this.setting2 = "default stuff as well";; //This is accessible!
function _printLog(msg) {
msg = msg || "";
$("#" + _divId).append(msg + "<br/>");
};
//this is **not** accessible - bc of return object below?
this.logSetting_priv = function () {
_printLog("PRIV: Setting1 is: " + _setting1);
_printLog("PRIV: Setting2 is: " + this.setting2);
};
/*
* Key Distinguishing feature of this pattern
*/
return {
printLog: function (msg) {
console.log("PRINTING:" + msg);
_printLog(msg);
},
logSetting_pub: function () {
this.printLog("PUB: Setting1 is: " + _setting1);
this.printLog("PUB: Setting2 is: " + this.setting2);
},
publicFunc2: function () {
_setting1 = "Fixed Deal returnFunction";
this.setting2 = "floating hamster";
}
};
};
//THIS DOESNT WORK!! . . . . bc of the return object??
LogSystem.prototype.publicFunc1 = function () {
_setting1 = "Fixed Deal";
this.setting2 = "floating midget";
};
/*******************************/
/*********Testing Code**********/
/*******************************/
$(document).ready(function () {
var logInst = new LogSystem();
//TESTING METHODS!
try {
logInst.publicFunc1(); //THIS DOESNT WORK!!
} catch (e) {
logInst.printLog("The call to the prototype function does not work - WHY?");
logInst.publicFunc2();
}
try {
logInst.logSetting_pub();
logInst.logSetting_priv();
} catch (e) {
logInst.printLog("ERR!!: " + e.message);
}
//TESTING MEMBERS!
logInst.printLog("We know this does not work? " + logInst._setting1); //undef
logInst.printLog("Why Does THIS WORK? " + logInst.setting2); //def
});
Thank you!
EDIT: Holy crap - and when I manipulate the prototype of the INSTANCE variable, i seem to break the whole object that was returned: http://jsfiddle.net/TvsW6/7/
If any one understands JS at this level, PLEASE explain that! :)
Thank you all so much. Obviously any one in this conversation is at a level way beyond "I do some jQuery" :)
Using private instance variables prevents you from using prototype (functions that need to access them need to be in the constructor body where the privates are declared with var) at the end of this answer is link to a pattern that implements protected. It may take some time to understand how prototpe works and would advice trying to understand the basic workings first before trying to mix it with closures to simulate private/public modifier.
Pointy answered you question correctly that when invoking a function with new but then returning an object would not return the Object referred to as this in the function:
function Test(){
this.name="some test";
return {name:"something else"};
}
console.log((new Test()).name);//name:something else
Not returning an object or returning a primitive (string, boolean, number) would cause the this object to be returned:
function Test(){
this.name="some test";
return "hello";
}
console.log((new Test()).name);//name:some test
Your constructor is returning a different object than the one build implicitly with new. Thus, inside the constructor this refers to a different object than the one you actually end up with outside, and that object doesn't have a property called "logSetting_priv".

need help understanding closures usage in this code

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...

calling a javascript function from a string passed to the function

i have seen multiple questions of a similar nature on here, yet none would work for the specific thing that i have (im using node.js). so for example take this code here.
function command_call(message, socket) {
if (message.length > 1){
var func = message[0];
var string = message.slice(1);
var string = string.join(' ')}
else{
var func = message[0];
var string = '';};
if(func[0] == '$') {
(eval(func.slice(1)))(string, socket);};
};
function say(string, socket){
socket.write(string)};
if the message passed in to the command_call were to be "$say hi" the function say would be called and return "hi". this works just fine however, if the function that was put to the eval does not exist, it crashes. for instance if the message passed to the command_call were to be "$example blah" it would try to eval "example". basically i need it to check if the function exists before it evals the function. and YES i want to use eval, unless there is a better way to do it in node. and again, this is in node.js
You should make an object of functions and use indexer notation:
var methods = {
$say: function() { ... }
};
if (!methods.hasOwnProperty(func))
// uh oh
else
methods[func]();

Extend $.mobile.changePage to accept more options?

I would like to extend $.mobile.changePage to accept more options such as adding a callback function for when the page finishes loading as well as more options for the AJAX call like contentType. Is there a way to do this without changing the source code? If not, I am willing to change the source code for educational purposes, but could not find it in the jQuery Mobile GitHub: https://github.com/jquery/jquery-mobile . Thanks for any helps or guidance.
One of the more exciting parts of JavaScript is that ability to redefine any function using a technique which is commonly referred to as Monkey Patching. (as an aside ES5 provides a new freeze method which allows developers to prevent such modifications.)
Here's an example of a JavaScript MonkeyPatch which allows us to modify the behaviour of a function without editing it's source:
// A namespace object.
var Example = {};
// Sums two values.
Example.sum = function (a, b) {
return a + b;
}
// Usage:
var result = Example.sum(1, 2);
Say we wanted to add logging to the sum method, we could just add a console.log line to the function, but we can also monkey patch it:
// Store a reference to the current 'Example.sum' function.
var originalSum = Example.sum;
// Now redeclare Example.sum...
Example.sum = function (a, b) {
// Call the originalSum function first...
var result = originalSum(a, b);
// Now add some logging...
console.log("Example.sum(" + a + ", " + b + ") yields " + result);
return result;
};
Now when Example.sum is called, not only will we get the result as before, but a console message will also be written. With this in mind, you can monkey patch the $.mobile.changePage method in the same way:
var originalChangePage = $.mobile.changePage;
// Redefine `changePage` so it accepts a 'complete' function in the options
// object which will be invoked when the page change is complete.
$.mobile.changePage = function (to, options) {
if (typeof options.complete === "function") {
$(body).one("pagechange", function (event) {
options.complete(event);
});
}
originalChangePage(to, options);
};

Categories

Resources