I was working on a function in JavaScript and i wondered if i could call a anonymous function later on:
code
more code
(function() {
alert('Hello World!');
})();
more code
(function() {
alert('Goodbye World!');
})();
//call to the first anonymous function
//call to the first anonymous function
Is it possible to call anonymous functions?
I imagine there could be an array containing all functions?
Since functions are "first class citizens" you can assign them to variables, or put them into arrays/objects whatever just like any other var, whether they're anonymous or not.
So you'll have to assign the anonymous function to a variable (or put it into an array) in order to have some kind of means to reference it later on.
Furthermore, you don't execute it immediately, rather you execute it at a later time.
var anon1 = (function(){
alert("anon1");
}); // <-- no () so it doesn't execute now.
// code code
anon1(); // <-- execute now
// ----- or -------
var myFuncs = [];
myFuncs.push( (function(){
alert("in myFuncs");
}) ); // <-- not executing it here.
// code code
myFuncs[0](); // <-- execute now
Related
I'm using PhantomJS v2.0 and CasperJS 1.1.0-beta3. I want to query a specific part inside the page DOM.
Here the code that did not work:
function myfunc()
{
return document.querySelector('span[style="color:#50aa50;"]').innerText;
}
var del=this.evaluate(myfunc());
this.echo("value: " + del);
And here the code that did work:
var del=this.evaluate(function()
{
return document.querySelector('span[style="color:#50aa50;"]').innerText;
});
this.echo("value: " + del);
It seems to be the same, but it works different, I don't understand.
And here a code that did also work:
function myfunc()
{
return document.querySelector('span[style="color:#50aa50;"]').innerText;
}
var del=this.evaluate(myfunc);
this.echo("value: " + del);
The difference here, I call the myfunc without the '()'.
Can anyone explain the reason?
The problem is this:
var text = this.evaluate(myfunc());
Functions in JavaScript are first class citizen. You can pass them into other functions. But that's not what you are doing here. You call the function and pass the result into evaluate, but the result is not a function.
Also casper.evaluate() is the page context, and only the page context has access to the document. When you call the function (with ()) essentially before executing casper.evaluate(), you erroneously try to access the document, when it is not possible.
The difference to casper.evaluate(function(){...}); is that the anonymous function is defined and passed into the evaluate() function.
There are cases where a function should be called instead of passed. For example when currying is done, but this is not applicable to casper.evaluate(), because it is sandboxed and the function that is finally run in casper.evaluate() cannot use variables from outside. It must be self contained. So the following code will also not work:
function myFunc2(a){
return function(){
// a is from outer scope so it will be inaccessible in `evaluate`
return a;
};
}
casper.echo(casper.evaluate(myFunc2("asd"))); // null
You should use
var text = this.evaluate(myfunc);
to pass a previously defined function to run in the page context.
It's also not a good idea to use reserved keywords like del as variable names.
I have a function with a variable called callback
function test(callback){
// Some code
callback;
}
When I call this function I used to insert a one liner into callback
eg. test($('#elem').hide());
Now I want to put multiple lines in here as the callback. I tried this but it does not appear to work.
var resetc = function(){
$('.access').removeClass('viz');
window.setTimeout(function(){
$('.access').find('.input.wheel').removeClass('viz');
$('.access').find('input').removeAttr('disabled');
},1000);
}
test(resetc);
As you are passing the function reference. You can use the callback variable to execute the function which it is referring. like
function test(callback) {
// Some code
callback();
}
You statement test($('#elem').hide()); is having no effect as you are passing the output of $('#elem').hide() to your method test and statement callback; actually is not performing anything.
You need to change your function call for test($('#elem').hide()); with
test(function() {
$('#elem').hide();
});
Your initial code doesn't do what you think. To call a callback, you need to put () after it:
function test(callback) {
// some code
callback();
}
If you fix that, test(resetc); will do what you want.
The reason you didn't notice this in your first test is because when you write
test($('#elem').hide());
you're executing $('#elem').hide() before calling test, it's not being done when test runs the callback. You need to pass a function to defer the execution until the callback is called:
test(function() {
$('#elem').hide();
});
I want to create a closure dynamically. See code below for explanation.
function myFunction(){
parentScopedVar(); //Would like to be able to call without using 'this'.
}
function myDynamicFunc(dynamicClosure){
//What do I need to do here to dynamically create
//a var called 'parentScopedVar' that can be referenced from myFunction?
myFunction.call(self);
}
myDynamicFunc(
{
parentScopedVar : function() { alert('Hello World'); }
});
Javascript uses lexical scope (based on where the code is declared), not dynamic scope.
If you are determined to try to do something that the language doesn't really encourage, you can force a string of code to be evaluated in your current execution context using eval(string of code here). In fact, you can do all sorts of odd things with eval(), but I'd much rather write code in a way that leverages the strengths of Javascript than to use a coding style that goes against the main design theme of the language (that's my opinion).
It's not entirely clear to me what problem you're trying to solve, but you can just pass a function as an argument and then call it via the argument from the called function.
// declare your function that takes a function reference an argument
function myFunction(callback) {
// call the function that was passed
callback();
}
function myDynamicFunc(){
// declare a local function
function myAlert() {
alert('Hello World');
}
// call your other function and pass it any function reference
myFunction(myAlert);
}
This will not pass an entire execution context. To do that, you'd have to package up the context in an object and pass a reference to the object, then dereference the properties from the object. That is typically how you pass an environment in JS.
You can use locally declared functions to provide access to parent scope from a callback (again lexical scope):
// declare your function that takes a function reference an argument
function doSomething(callback) {
// call the function that was passed
callback();
}
function myFunc() {
var myLocal1 = "Hello";
var myLocal2 = "World";
function callback() {
// when this is called, it has access to the variables of the parent scope
alert(myLocal1 + " " + myLocal2);
}
doSomething(myFunc);
}
You can even use it as a lasting closure:
// declare your function that takes a function reference an argument
function doSomething(callback) {
// call the function that was passed
callback();
}
function myFunc() {
var myLocal1 = "Hello";
var myLocal2 = "World";
function callback() {
// when this is called, it has access to the variables of the parent scope
// which are still alive in this closure even though myFunc has finished
// executing 10 minutes ago
alert(myLocal1 + " " + myLocal2);
}
// call the callback function 10 minutes from now,
// long after myFunc has finished executing
setTimeout(callback, 10 * 60 * 1000);
}
Here are some reference articles on lexical and dynamic scope in Javascript:
Is it possible to achieve dynamic scoping in JavaScript without resorting to eval?
Are variables statically or dynamically "scoped" in javascript?
What is lexical scope?
i want to pass a function to another function as a parameter.
I want to do that because the latter function calls an async Jquery method and AFTER that gives a result back, i want some javascript code executed.
And because this function is called from multiple places, i want the code to execute (after the async Jquery code gets executed) to be passed in the function.
Makes sense? i hope :)
Now what is see is that the order in which the code is executed is noth what i want.
I've simplified the code to this code:
$('#AddThirdParty').click(function() {
var func = new function() {
alert('1');
alert('2');
alert('3');
}
alert('4');
LoadHtml(func);
alert('5');
});
function LoadHtml(funcToExecute) {
//load some async content
funcToExecute;
}
Now what i wanted to achieve (or at least what i thought would happen) was that alert4 would fire, then the loadhtml would fire alert1, alert2 and alert3, and then the code would return to alert5.
But what happens is this: alert1, alert2, alert3, alert4, alert5.
Does anyone know what i'm doing wrong and why this is the order in which the code is executed?
It looks like the alert1..alert3 gets executed when i define the new function(), but why doesn't it ALSO get executed when i call it from the LoadHtml function?
$('#AddThirdParty').click(function() {
var func = function() { // NOTE: no "new"
alert('1');
alert('2');
alert('3');
}
alert('4');
LoadHtml(func);
alert('5');
});
function LoadHtml(funcToExecute) {
//load some async content
funcToExecute(); // NOTE: parentheses
}
Two errors: the syntax for anonymous functions does not include the keyword new; and JavaScript requires parentheses for function calls, even if functions do not take any arguments. When you just say funcToExecute, that is just a variable giving its value in a context where nothing is using that value (kind of like writing 3; as a statement).
You might notice that you already know how to use anonymous functions: you did not write $('#AddThirdParty').click(new function() ...);
$('#AddThirdParty').click(function() {
var func = new function() {
alert('1');
alert('2');
alert('3');
}
alert('4');
LoadHtml(func);
alert('5');
});
function LoadHtml(funcToExecute) {
//load some async content
funcToExecute;
}
The new keyword creates an object from the function. This means the function (which is anonymous) gets called immediatly. This would be the same as
var foo = function() {
alert("1");
alert("2");
alert("3");
}
var func = new foo();
This means your creating a new object (not a function!) and inside the constructor your alert 1,2,3. Then you alert 4. Then you call LoadHtml which does nothing, then you alert 5.
As for
funcToExecute;
The funcToExecute is just a variable containing a function. It actually needs to be executed.
I have two external .js files. The first contains a function. The second calls the function.
file1.js
$(document).ready(function() {
function menuHoverStart(element, topshift, thumbchange) {
... function here ...
}
});
file2.js
$(document).ready(function() {
setTimeout(function() { menuHoverStart("#myDiv", "63px", "myIMG"); },2000);
});
The trouble is that this is not running the function. I need the two separate files because file2.js is inserted dynamically depending on certain conditions. This function works if I include the setTimeout... line at the end of file1.js
Any ideas?
The problem is, that menuHoverStart is not accessible outside of its scope (which is defined by the .ready() callback function in file #1). You need to make this function available in the global scope (or through any object that is available in the global scope):
function menuHoverStart(element, topshift, thumbchange) {
// ...
}
$(document).ready(function() {
// ...
});
If you want menuHoverStart to stay in the .ready() callback, you need to add the function to the global object manually (using a function expression):
$(document).ready(function() {
window.menuHoverStart = function (element, topshift, thumbchange) {
// ...
};
// ...
});
You have declared menuHoverStart inside a function (the anonymous one you pass to the ready ready). That limits its scope to that function and you cannot call it from outside that function.
It doesn't do anything there, so there is no need to hold off on defining it until the ready event fires, so you could just move it outside the anonymous function.
That said, globals are worth avoiding, so you might prefer to define a namespace (to reduce the risk of name collisions) and hang the function off that.
var MYNAMESPACE = {}; // In the global scope, not in a function
// The rest can go anywhere though
MYNAMESPACE.menuHoverStart = function (element, topshift, thumbchange) {