In JavaScript, is it possible to move inner functions from one function into the global scope? I haven't yet found any straightforward way to do this.
function moveMethodsIntoGlobalScope(functionName){
//move all of functionName's methods into the global scope
//methodsToPutIntoGlobalScope should be used as the input for this function.
}
//I want all of the methods in this function to be moved into the global scope so that they can be called outside this function.
function methodsToPutInGlobalScope(){
function alertSomething(){
alert("This should be moved into the global scope, so that it can be called from outside the function that encloses it.");
}
function alertSomethingElse(){
alert("This should also be moved into the global scope.");
}
}
If you don't want to make changes in methodsToPutInGLobalSpace you can use the following dirty hack:
var parts = methodsToPutInGlobalScope.toString().split('\n');
eval(parts.splice(1, parts.length - 2).join(''));
As final solution we can use:
moveMethodsIntoGlobalScope(methodsToPutInGlobalScope);
alertSomething(); //why doesn't this work?
function moveMethodsIntoGlobalScope(functionName){
var parts = functionName.toString().split('\n');
eval.call(window, parts.splice(1, parts.length - 2).join(''));
}
//I want all of the methods in this function to be moved into the global scope so that they can be called outside this function.
function methodsToPutInGlobalScope(){
function alertSomething(){
alert("This should be moved into the global scope, so that it can be called from outside the function that encloses it.");
}
function alertSomethingElse(){
alert("This should also be moved into the global scope.");
}
}
Live demo
Not very sophisticated, but would work.
function copyInto(arr, context) {
//move all of functionName's methods into the global scope
//methodsToPutIntoGlobalScope should be used as the input for this function.
for (var i = 0; i < arr.length; i += 2) {
var exportName = arr[i];
var value = arr[i + 1];
eval(exportName + "=" + value.toString());
}
}
//I want all of the methods in this function to be moved into the global scope so that they can be called outside this function.
function methodsToPutInGlobalScope() {
function alertSomething() {
alert("This should be moved into the global scope, so that it can be called from outside the function that encloses it.");
}
function alertSomethingElse() {
alert("This should also be moved into the global scope.");
}
copyInto(["alertSomething", alertSomething, "alertSomethingElse", alertSomethingElse], window);
}
methodsToPutInGlobalScope();
alertSomething();
alertSomethingElse();
Yes, this is possible. If you declare a variable using var keyword that variable becomes local only, but if you don't it becomes a global one.
function foo(){
var test = 'test'; // <- Using var keyword
}
foo(); // <- execute the function
console.log(test); // undefined
But if we do the same thing without var keyword:
function foo(){
test = 'test'; // <- Using var keyword
}
foo(); // <- execute the function
console.log(test); // test
In order to make your inner functions global, you'd declare anonymous functions without var keyword
function methodsToPutInGlobalScope() {
alertSomething = function () {
alert("This should be moved into the global scope, so that it can be called from outside the function that encloses it.");
}
alertSomethingElse = function () {
alert("This should also be moved into the global scope.");
}
}
methodsToPutInGlobalScope(); // <- Don't forget to execute this function
alertSomething(); // Works
alertSomethingElse(); // Works as well
Related
Any function within function forms a closure. Do closures always needs to be in an immediately invoked function?
The first example is where a closure is formed within an iife and works as expected, gives "8" and "7" as output.
var cat = (function (){
var lives = 9;
return function() {
return --lives;
}
}());
console.log("iife");
console.log(cat());
console.log(cat());
In the below example the closure does not work as expected, prints the same value every time.
var cat = function (){
var lives = 9;
return function() {
return --lives;
}
};
console.log("no iife");
console.log(cat()());
console.log(cat()());
A closure is just the link between a function and the scope in which it was created, link which exists when the function uses a variable from this scope.
You have this problem because you don't keep the closure: you're recreating it at every console.log when you call cat().
Change
console.log(cat()());
console.log(cat()());
into
let c = cat();
console.log(c());
console.log(c());
function hello() {
var result = [];
var str = 'I am here';
function inner() {
var result = [];
for (var i=0;i<10;i++) {
result.push(i);
}
return result;
}
}
in the code above when I called the function hello(), the return value was an empty [], also it did not console.log the str from the inner function. However, in the below code set I have used a call back function:
function forEach(cb) {
for(var i =0;i<10;i++) {
cb(i);
}
}
function hello() {
var result = [];
var str = 'I am here';
forEach(function(num) {
console.log(str);
result.push(num);
});
return result;
}
the question is why both functions reacted, and gave a different output? Note; in both codes there was an inner function which supposed to create a new scope that can access the outer scope ? Does anyone have a good explanation for this issue ?
Thanks
In the first code block, inner is a new function that is declared inside of hello. It does not execute because you do not call it. It does create a new child scope inside of hello when it is called. But, since hello() doesn't actually return anything and doesn't call inner(), you get undefined when you call hello(). You could fix that by changing to this (you can run this snippet to see the return value):
function hello() {
var str = 'I am here';
// declare inner
function inner() {
var result = [];
for (var i = 0; i < 10; i++) {
result.push(i);
}
return result;
}
// now call inner() and return its result
return inner();
}
console.log(hello());
Functions declared inside other functions do create a new scope. Every function declaration and corresponding call in Javascript creates a new scope. If the function is inside another function, then the code inside that inner function has access to both its local scope and to the parent scope and this can nest as deep as your nested function declarations go.
the question is why both functions reacted, and gave a different
output? Note; in both codes there was an inner function which supposed
to create a new scope that can access the outer scope ? Does anyone
have a good explanation for this issue ? Thanks
In the first example, you never called the inner function so it never executed.
In the second example, you pass an inline, anonymous function reference as a function argument to your forEach() function. When that forEach() function executes, it calls your callback function with the line of code cb(i) so that's how your callback function is getting called in the second example. forEach() calls it for you.
Also, in the second example, the locally declared callback function is accessing the parent scope and modifying the result array (which is perfectly allowable). In your first code example, you are declared a new result variable in the inner function scope and then returning that. You are not accessing the parent result variable. When you declare a local variable with the same name as a variable in the parent scope, the local variable overrides the parent variable (essentially hiding the parent variable) and any references to that variable in the local scope only access the local variable.
You could have written the first code example to use a parent scoped result variable like this:
function hello() {
var result = [];
var str = 'I am here';
// declare inner
function inner() {
for (var i = 0; i < 10; i++) {
result.push(i);
}
return result;
}
// now call inner() and return result
inner();
return result;
}
console.log(hello());
You have confused function declaration and calling.
Declaring a function can be done in multiple ways:
function myNewFunction() {}
Now this function exists in the current scope, but will not execute unless called.
You can call the function like this. Now your function will get executed.
myNewFunction();
Functions and their scopes can be compared to variables. Functions defined inside another function can only be accessed from inside the parent function. Let me give you an example.
function myMegaFunction() {
console.log("in mega");
function mySmallFunction() {
console.log("in small");
}
}
myMegaFunction();
This will only print - 'in mega'. If you call mySmallFunction() inside of myMegaFunction then both lines will get printed.
Now let's take a more complex scenario like this:
function myMegaFunction() {
console.log("in mega");
var str = "car";
var result = function mySmallFunction() {
console.log("in a small", str);
}
return result;
}
var resultingFunction = myMegaFunction();
resultingFunction();
This will first print the following:
in mega
in a small car
So essentially, this is functions being passed around like variables. They can be executed later on too.
i'm learning about functions. i'm confused in one scenario.
suppose i have three functions
<script>
var fnRef = function() {
console.log("i'm function with no name but refered to fnRef");
};
var funRef2 = function test() {
console.log("im test reffered to funRef2");
};
function test2() {
console.log("i'm test2 named function")
};
</script>
fnRef, fnref2 and test2 will be assigned to window as a property as fnRef and fnRef2 are variable and test2 is named function that act as variable.
but why test2 is not assigned to the global object(window) when refered by funref2? and why i'm not able to execute test(); can someone tell me what is happening in detail.
The named function expression is useful so you can access the function inside it's own scope without using arguments.callee, and it also makes it easier when debugging as the name can be seen in stack traces, breakpoints etc.
This name is then local only to the function bodys scope, meaning
var test1 = function test2() {
if (something) test2(); // available in this scope only
}
test2(); // not here
You can't call the function by it's name, only by the variable it's assigned to, as the functions name is limited to the functions scope when it's a function expression.
When defining a function declaration, the name is assigned to the current scope, and hoisted, so this
var bar = test();
function test() { return 'foo'; }
is more or less turned into this
var test = function() { return 'foo'; }
var bar = test();
Is there a way to print the value of temp (a closure variable) from a function defined outside the closure but referenced within the closure without passing temp as a variable to funcA?
var funcA, funcB;
funcA = function () {
console.log(temp);
}
funcB = function () {var temp, funcC;
temp = 1;
funcC = funcA;
funcC();
}
funcB(); // temp is undefined.
This works, but only because funcA is defined within funcB:
funcB = function () {var temp, funcA, funcC;
temp = 1;
funcA = function () {
console.log(temp);
}
funcC = funcA;
funcC();
}
funcB(); // 1
I'm trying to find a way to pull some function definitions out of outer functions to streamline code that's getting a little complex. Can I define funcA outside of funcB but still reference the temp variable without having to pass parameters?
I read that javascript does not have dynamic run time scoping, that it's only lexical scoping, but with referencing a function (funcA via funcC) within funcB, is there a way to meet the lexical scope requirement and provide access to the scoped variables for funcB?
Using Akinkunle Allen's comment, I came up with this which seems to solve my problem.
function funcB () {
var funcA, funcB, temp;
funcA = function () {
console.log(temp);
}
funcB = function () {var funcC;
temp = 1;
funcC = funcA;
funcC();
}
return funcB();
}
funcB(); // 1
Yes, and No.
The keyword var for declaring variables behaves different depending upon what the current scope is. When var is executed on the global scope it is optional. The variable becomes a property of the global object. When executing in the browser this global object is window.
So the following in global space has the same result.
var temp = 1;
window.temp = 1;
this.temp = 1;
All the above is just window.temp because of the global context.
When you use var inside a function then the variable is attached to the function. All functions in Javascript are objects so local var variables will live as long as the parent function is still being used somewhere.
Javascript will walk the hierarchy of executing scopes to find a variable identifier. So any inner functions can access their outer function variables (as in your example).
What you can do is play around with the this reference in functions.
The identifier this in Javascript is dynamic (meaning that you can change it). I can pass a variable to an unknown function that was declared outside the calling function. Since the this.temp is used to reference the variable the function funcA is able to display the value.
funcB = function(otherFunc)
{
this.temp = 1;
otherFunc();
}
funcA = function()
{
alert(this.temp);
}
funcB(funcA);
http://jsfiddle.net/thinkingmedia/dfLvj/
See the above jsfiddle example.
What you can do with this is change the meaning of this on the fly. Here is a better example.
funcB = function(otherFunc)
{
var temp = {
message: "Hello World!"
};
var foo = otherFunc.bind(temp);
foo();
}
funcA = function()
{
alert(this.message);
}
funcB(funcA);
http://jsfiddle.net/thinkingmedia/K5Pw6/
Dynamically changing this can have a lot of benefits by allowing a function to accept closure references that will be executed with a custom this reference.
An example might be a click event handler where this is the DOM element that triggered the event.
I can't manage to change the value of 'i' no matter how hard I try...
My code is the following:
function changeValue(){
//neither 'var i=99;' or 'i=99;' interferes with the 'i' on myFunction
}
function myFunction(){
var i;
for(i=0;i<3;i++){
alert(i);
changeValue();
alert(i);
}
}
myFunction();
My question: How can I change the value of 'i' (on MyFunction) using the changeValue function?
Also: I badly need read some guides about this, could someone give me a link to a good one?
Move changeValue() to be in the same scope as i:
function myFunction(){
var i;
for(i=0;i<3;i++){
alert(i);
changeValue();
alert(i);
}
function changeValue() { i = 99; }
}
Or, put i in the same scope as changeValue():
var i;
function changeValue() { i = 99; }
function myFunction(){
// var i; // don't define i here
for(i=0;i<3;i++){
alert(i);
changeValue();
alert(i);
}
}
Alternatively, you can tell changeValue() what the value of i is, then have it return the new value:
function changeValue(i) {
return i + 1;
}
Then:
i = changeValue(i);
Edit: To illustrate scope:
var a = 0; // global scope - accessible everywhere via a
// unless overridden by a locally scoped a
// always accessible via window.a
function doSomething () {
var a = 1; // local scope - you can still access window.a
var b = 2; // local scope - accessible to child scopes, but not global scope
function innerFunction () {
var a = 3; // you no longer have access to the parent function's a variable
// you can still access window.a
var c = 4; // only accessible here (since no child scopes exist)
alert(window.a); // 0
alert(a); // 3
alert(b); // 2
alert(c); // 4
}
innerFunction();
alert(window.a); // 0
alert(a); // 1
alert(b); // 2
alert(c); // undefined - unavailable in this scope
}
doSomething();
alert(window.a); // 0
alert(a); // 0
alert(b); // undefined - unavailable in this scope
alert(c); // undefined - unavailable in this scope
You could simply return the value :
function changeValue(i) {
return i + 2;
}
for(i=0;i<3;i++){
alert(i);
i = changeValue(i);
alert(i);
}
function myFunction(){
var i;
for(i=0;i<3;i++){
alert(i);
i = changeValue();
alert(i);
}
}
while changeValue():
changeValue(){
return new_i;
}
You can only manipulate variables that are inside your scope. Currently, the scope of i is confined to myFunction().
This is an excellent article to get you started understanding the scope rules in JavaScript.
Both changeValue and myFunction exist in the global scope. If you define i in myFunction, it's only accessible inside myFunction and its children, functions defined inside myFunction. The 'scope chain' (I'm just thinking up a word for it) looks like this:
myFunction <- window
changeValue also exists in the global scope. It is called from myFunction, but that doesn't change the scope in which it exists. Its scope chain is like this:
changeValue <- window
If you only use changeValue inside myFunction, you can do this:
function myFunction() {
function changeValue() { /* stuff */ }
/* more stuff */
}
changeValue's scope chain is now like this:
changeValue <- myFunction <- window
As i exists in myFunction, it now also exists in changeValue.
when you are using var within myFunction, it becomes a local variable in that scope. So you can't access it anywhere outside not matter how hard you try.
Use window.i instead of var i in both places and it should work,
You can simply avoid window. and use i directly without var prefix or even place the var i declaration outside both the functions... but effectively the variable become a part of the window object. (In general all global variable in JS are part of the window object)