Javascript call with dynamic closure - javascript

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?

Related

How to access a scoped function

I'm trying to find a way of accessing a scoped function - take this code for example:
(function() {
one();
console.log('IIFE END');
function scoped() {
console.log('scoped');
}
scoped();
})();
function one() {
console.log('one');
}
scoped(); // error
How can I access the call to the function to prevent the error? Using the return keyword fails
What you're doing is more or less saying "I locked the keys in the car. How do I access the keys." You can't. You locked them up in a way that makes them impossible to retrieve (well, unless you break the window, but you get my point). If you could simply open the door to get the keys there wouldn't be any point to locking the car.
That "scoped" function is the keys locked in the car.
What you want to do, is declare "scoped" outside of that anonymous function (before it, actually). Now, you can call it from within your anon function and outside of it.
You could either:
let scope;
...in anon function...
{
scope = { ...some function };
}
or
const scope = { some function }
... in anon function
scope();
Either way, outside of the anon function, you can now call "scope ()".
I guess I would add, that in JS, it's almost always possible to grab something that isn't intended to be grabbed. You could probably work with a top-level "this", or something, or just name your anon function (so essentially creating a named object that is of type function) and accessing the members of it by bracket notation. You would probably have to remove the immediate return though and call it in another line of code (after the function declaration).
But that's all hackery voodoo. You're breaking the window. In the day to day, what you say you want to do here is by design verboten.
Depending on how flexible you are, you can do this:
const scoped = (function() {
one();
console.log('IIFE END');
function scoped() {
console.log('scoped');
}
scoped();
return scoped;
})();
function one() {
console.log('one');
}
scoped(); // NO error :)
Or if your function's return is reserved for something else, just do this:
var scoped; // If you don't want this pre-declaration, you can just use a global scope instead (e.g. window.scoped)
(function() {
one();
console.log('IIFE END');
scoped = function() {
console.log('scoped');
}
scoped();
})();
function one() {
console.log('one');
}
scoped(); // NO error :)

Is the anonymous function inside a callback invoked using iife?

I am trying to understand how an anonymous function inside of a callback function is invoked.
For example:
const callbackExample = function(param, callback) {
console.log('This is an example of a callback function');
callback(param);
};
callbackExample('What', function(param) {
console.log(param);
})
My question is how does a anonymous function get invoked? If I substitute the callback to equal the anonymous function below.
Is the callback being substituted for the anonymous function.
Does the callback === function(param) { console.log(param) }
What I mean is I cannot invoke the function like this.
function() { console.log('Not') } ();
There are only three ways to declare and invoke a function.
assign a anonymous function a name: function expression
give a function a name: function declaration
Immediate Invocation function express
My theory is when not using a function express or function declaration for the callback function then Javascript parses the code and detects a anonymous function and uses iife to invoke the anonymous function.
I cannot find anything on the internet nor an api that describes what is happening behind the scenes, so I ask can somebody explain this to me.
IIFE (immeadiately invoked function expression) is just a name coined by the community for this specific construct:
(function() { /*...*/ })()
It's a function expression, that is directly followed by a function call to that function. That's it. You don't have an IIFE in your code.
My question is how does a anonymous function get invoked?
Functions get invoked using a reference to them, their name is just a debugging feature (and it's a reference to the function itself inside the functions body). Functions don't need a name:
let test = function /*irrelevant*/ () { };
let test2 = test;
test(); test2();
If you use a function declaration, the name is not only used as the function name, but also as the name of a variable that references the function:
function named() { }
is barely equal to (let's ignore "hoisting" here):
var named = function named() { }
If you invoke a function using a function expression as one of it's arguments:
function called(reference) { }
called(function irrelevant() { })
then the function expression gets evaluated, a function gets created, and a reference to it gets passed to the called function as an argument, which can then be accessed using the reference variable.

Declaring a callback function which uses a function from a closure and executing the callback function inside that closure throws error [duplicate]

So i was playing around with the concept of callbacks and i ran into a situation where I wanted to make sure i knew what i thought was happening, was actually happening.
function greet(callback) { // 'greet' function takes a callback
var greeting = "hi"; // 'greeting' variable is set in the scope
callback() // 'callback' function is invoked
}
greet(
function() {
console.log(greeting)
});
//Console logs nothing
Sorta weird, you'd expect the callback() to look in its next closest scope and figure out what greeting is. However, once i declare the greeting variable to the global execution context, greeting is logged in the console.
var greeting = 'hi' // 'greeting' variable is set in global context
function greet(callback) { // 'greet' function takes a callback
callback() // 'callback' function is invoked
}
greet(
function() {
console.log(greeting)
});
//Console logs: 'hi'
Is this because technically the callback() function that's logging the variable is actually defined in the global context and is simply being invoked inside of greet()? So it's not going to look inside of greet() first, like a normal function expression would, but right into the global context because that's where it's defined.
I just wanted to make sure i understand what's happening here and not some weird scope/block issue that i don't realize.
You're right - the function has access to the scope which it is defined in.
Your example is effectively this (moving your callback to its own function):
var greeting = 'hi';
function greet(callback) {
callback();
}
function logGreeting() {
console.log(greeting);
}
greet(logGreeting);
As you can see, logGreeting has access to greeting at this point because it is defined in the same (or higher) scope.
However, when we move greeting into the greet function:
function greet(callback) {
var greeting = 'hi';
callback();
}
function logGreeting() {
console.log(greeting);
}
greet(logGreeting);
greeting is no longer in the same or higher scope to logGreeting, it's in a different scope entirely, so logGreeting cannot look upwards through the scope in order to find greeting.
The scope which logGreeting has access to is the scope in which it is defined rather than which it is called, so it doesn't evaluate the scope when it's called with callback() like you mentioned in your question.
That's an example of lexical scope which is how JavaScript handles scope, as opposed to dynamic scope. In a nutshell lexical scope determines the context based on where things are defined and dynamic is based on where it's called.
For your first example to work like you thought would be dynamic scope.
You can read a bit more detail here in the "Lexical scope vs. dynamic scope" section.
https://en.wikipedia.org/wiki/Scope_(computer_science)
Javascript uses Static Scoping
TLDR; Variables are resolved according to their location in the source code.
greeting is only defined with the closure of the greet function. Only code defined within the greet function closure can see the greeting variable.
function greet(callback) { // 'greet' function takes a callback
var greeting = "hi"; // 'greeting' variable is set in the scope
callback() // 'callback' function is invoked
}
greet(function() {
console.log(greeting)
});
Here though, greeting is defined in a scope accessible by the nested closures of the greet function and the anonymous function used in the console.log call.
var greeting = 'hi' // 'greeting' variable is set in global context
function greet(callback) { // 'greet' function takes a callback
callback() // 'callback' function is invoked
}
greet(function() {
console.log(greeting)
});
NOTE: this keyword has a different set of rules.

Callback/scope understanding

So i was playing around with the concept of callbacks and i ran into a situation where I wanted to make sure i knew what i thought was happening, was actually happening.
function greet(callback) { // 'greet' function takes a callback
var greeting = "hi"; // 'greeting' variable is set in the scope
callback() // 'callback' function is invoked
}
greet(
function() {
console.log(greeting)
});
//Console logs nothing
Sorta weird, you'd expect the callback() to look in its next closest scope and figure out what greeting is. However, once i declare the greeting variable to the global execution context, greeting is logged in the console.
var greeting = 'hi' // 'greeting' variable is set in global context
function greet(callback) { // 'greet' function takes a callback
callback() // 'callback' function is invoked
}
greet(
function() {
console.log(greeting)
});
//Console logs: 'hi'
Is this because technically the callback() function that's logging the variable is actually defined in the global context and is simply being invoked inside of greet()? So it's not going to look inside of greet() first, like a normal function expression would, but right into the global context because that's where it's defined.
I just wanted to make sure i understand what's happening here and not some weird scope/block issue that i don't realize.
You're right - the function has access to the scope which it is defined in.
Your example is effectively this (moving your callback to its own function):
var greeting = 'hi';
function greet(callback) {
callback();
}
function logGreeting() {
console.log(greeting);
}
greet(logGreeting);
As you can see, logGreeting has access to greeting at this point because it is defined in the same (or higher) scope.
However, when we move greeting into the greet function:
function greet(callback) {
var greeting = 'hi';
callback();
}
function logGreeting() {
console.log(greeting);
}
greet(logGreeting);
greeting is no longer in the same or higher scope to logGreeting, it's in a different scope entirely, so logGreeting cannot look upwards through the scope in order to find greeting.
The scope which logGreeting has access to is the scope in which it is defined rather than which it is called, so it doesn't evaluate the scope when it's called with callback() like you mentioned in your question.
That's an example of lexical scope which is how JavaScript handles scope, as opposed to dynamic scope. In a nutshell lexical scope determines the context based on where things are defined and dynamic is based on where it's called.
For your first example to work like you thought would be dynamic scope.
You can read a bit more detail here in the "Lexical scope vs. dynamic scope" section.
https://en.wikipedia.org/wiki/Scope_(computer_science)
Javascript uses Static Scoping
TLDR; Variables are resolved according to their location in the source code.
greeting is only defined with the closure of the greet function. Only code defined within the greet function closure can see the greeting variable.
function greet(callback) { // 'greet' function takes a callback
var greeting = "hi"; // 'greeting' variable is set in the scope
callback() // 'callback' function is invoked
}
greet(function() {
console.log(greeting)
});
Here though, greeting is defined in a scope accessible by the nested closures of the greet function and the anonymous function used in the console.log call.
var greeting = 'hi' // 'greeting' variable is set in global context
function greet(callback) { // 'greet' function takes a callback
callback() // 'callback' function is invoked
}
greet(function() {
console.log(greeting)
});
NOTE: this keyword has a different set of rules.

Is it possible to export a value of an variable from one javascript to an other?

I have made a Web page using jquery and php where all files are used in a modular style. Now I have two JavaScript files which must communicate with each other. One Script generates a variable (id_menu_bar) which contains a number. I want that this variable gets transported to the second JavaScript and is used there.
How do I make that?
Here the Script
menu_bar.js
$(document).ready(function() {
function wrapper_action(id_menu_bar) {
$(".wrapper").animate({height: "0px"});
$("#changer p").click(function() {
$(".wrapper").animate({height: "300px"});
});
}
$("#select_place li").live("click", function() {
var wrapper_id = $(".wrapper").attr("id");
var id_place = this.id;
if (wrapper_id != "place")
{
$("#select_level li").remove();
$("#select_building").load("menu_bar/menu_bar_building.php?placeitem="+id_place, function() {
$("#select_building li").click(function() {
var id_building = this.id;
if (wrapper_id != "building")
{
$("#select_level").load("menu_bar/menu_bar_level.php?buildingitem="+id_building, function() {
$("#select_level li").click(function() {
var id_level = this.id;
wrapper_action(id_level);
});
});
}
else if (wrapper_id == "building")
{wrapper_action(id_building);}
});
});
}
else if (wrapper_id == "place")
{wrapper_action(id_place);}
});
});
if the variable id_menu_bar is in global scope then it can be used by another script on the page.
jQuery's $.data() is also good for storing data against elements and means that you do not need to use a global variable and pollute the global namespace.
EDIT:
In response to your comment, there is a difference in how you declare variables that determines how they are scoped in JavaScript.
Global Variables
Outside of a function declaring a variable like
var myVariable;
or
myVariable;
will make no difference - both variables will have global scope. In fact, the second approach will give a variable global scope, even inside of a function. For example
function firstFunction() {
// Local scope i.e. scoped to firstFunction
var localVariable;
// Global scope i.e. available to all other JavaScript code running
// in the page
globalVariable = "I'm not really hiding";
}
function secondFunction() {
// I can access globalVariable here but only after
// firstFunction has been executed
alert(globalVariable); // alerts I'm not really hiding
}
The difference in this scenario is that the alert will fail and not show the value for globalVariable upon execution of secondFunction() until firstFunction() has been executed, since this is where the variable is declared. Had the variable been declared outside of any function, the alert would have succeeded and shown the value of globalVariable
Using jQuery.data()
Using this command, you can store data in a cache object for an element. I would recommend looking at the source to see how this achieved, but it is pretty neat. Consider
function firstFunction() {
$.data(document,"myVariable","I'm not really hiding");
globalVariable = "I'm not hiding";
}
function secondFunction() {
// alerts "I'm not really hiding" but only if firstFunction is executed before
// secondFunction
alert($.data(document, "myVariable"));
// alerts "I'm not hiding" but only if firstFunction is executed before
// secondFunction
alert(globalVariable);
}
in this scenario, a string value "I'm not really hiding" is stored against the document object using the key string myVariable in firstFunction. This value can then be retrieved from the cache object anywhere else in the script. Attempting to read a value from the cache object without having first set it will yield undefined.
Take a look at this Working Demo for more details.
For reasons not to use Global Variables, check out this article.
Does it have to ve a JavaScript variable?
Can you store the information using the .data() function against a relevant element?

Categories