Is it possible to do what I want? the changeEl() function is also in fadeGall()
function initOpen(){
$('ul.piple-holder > li > a, ul.work-holder > li > a').each(function(){
var _box = $(this);
_box.click(function(){
//SOME CODE HERE TO RUN changeEl(0); on each _hold
//element from fadeGall()
});
});
}
function fadeGall(){
var _hold = $('div.work-info');
_hold.each(function(){
var _hold = $(this);
function changeEl(_ind){
return;
}
});
}
No idea what you're trying to do, but if you are asking if it's okay to define a function inside of another one, sure, it is. Just be aware that the nested function won't be callable outside of the function it was defined in.
You can nest a function within a function. The nested (inner) function is private to its containing (outer) function. It also forms a closure.
A closure is an expression (typically
a function) that can have free
variables together with an environment
that binds those variables (that
"closes" the expression).
reference
Since a nested function is a closure, this means that a nested function can "inherit" the arguments and variables of its containing function. In other words, the inner function contains the scope of the outer function.
To summarize:
The inner function can be accessed only from statements in the outer function.
The inner function forms a closure: the inner function can use the arguments and variables of the outer function, while the outer function cannot use the arguments and variables of the inner function.
The following example shows nested functions:
function addSquares(a,b) {
function square(x) {
return x * x;
}
return square(a) + square(b);
}
a = addSquares(2,3); // returns 13
b = addSquares(3,4); // returns 25
c = addSquares(4,5); // returns 41
Since the inner function forms a closure, you can call the outer function and specify arguments for both the outer and inner function:
function outside(x) {
function inside(y) {
return x + y;
}
return inside;
}
fn_inside = outside(3);
result = fn_inside(5); // returns 8
result1 = outside(3)(5); // returns 8
Related
If I define an inner function inside a function, the inner function has access to the outer function's variables. If I want this inner function to be reusable and define it outside the outer function, the inner function now loses access to the outer function variables. How do I make this new reusable inner function have access to outside function variables, without passing those variables in as parameters?
function a () {
var x = [[1,2,3], [1,2,3], [1,2,3]];
var keys = Object.keys(x[0]);
for (var i = 0; i < x.length; i++) {
angular.forEach(keys, loop);
}
}
function loop (key) {
console.log(key, i);//i is undefined here
}
a();
Specifically, is there some way without 1) assigning variables to this, 2) without passing in variables as parameters, and 3) without creating global variables?
Edit: It seems there is no way to do this. But if I try another approach, to have the reusable function return a new function, I also do not have access to the inner scope. Why is this, and is there some way to make this work?
function a () {
var x = [[1,2,3], [1,2,3], [1,2,3]];
var keys = Object.keys(x[0]);
var myloop = loop();
for (var i = 0; i < x.length; i++) {
angular.forEach(keys, myloop);
}
}
function loop (key) {
return function(key) {
console.log(key, i);//i is undefined here
};
}
a();
In the following example, loop returns a function that closes over the value of i.
function a () {
var x = [[1,2,3], [1,2,3], [1,2,3]];
var keys = Object.keys(x[0]);
for (var i = 0; i < keys.length; i++) {
keys.forEach(loop(i));
}
}
function loop (i) {
return function (key) {
console.log(key, i); // i is now defined
}
}
a();
Output:
0 0
1 0
2 0
0 1
1 1
2 1
0 2
1 2
2 2
How do I make this new reusable inner function have access to outside function variables, without passing those variables in as parameters?
You can't. JavaScript has lexical scope, not dynamic scope.
See also: What is lexical scope?
I also want to make another option known which I just discovered. If you use .bind, you can curry the function with i, and the other variables will be passed in after the curried parameters.
....
angular.forEach(keys, loop.bind(null, i));
...
function loop(i, key) {
...
}
Inner functions are treated locally by the outer function. Therefore, you can access the variables belonging to the outer function from the inner function. But, once you have the inner function as a separate function outside the outer function, then you no longer have access to the private data variables of the outer function.
If this seems complicated, here is an example:
function A
{
//variables
function B
{
can use variables of A
}
}
But,
function A
{
//variables
}
function B
{
//cannot access variables of A
}
In JS (and many other languages), there is a visibility context. Possible contexts are e.g. "global" or function or block. These contexts are hierarchical, inner can read outer. Outer can never read inner (encapsulation principle) unless inner declares variable as global.
If I have a function inside another function but the inner function doesn't use the outer function's variables, will the inner function still be a closure?
function someFunc(){
return function(){
\\do some more stuff
}
}
Whenever you see the function keyword within another function, the inner function has access to variables in the outer function.
function foo(x) {
var tmp = 3;
function bar(y) {
alert(x + y + tmp);
}
bar(5);
}
foo(2);
This will always alert 10, because bar can access the x which was defined as an argument to foo, and it can also access tmp from foo.
For info about closures, refer: http://javascriptissexy.com/understand-javascript-closures-with-ease/
Consider the following JavaScript code:
function getFunction(x) {
var closureMember = x;
return function() {
return closureMember * 2;
};
}
var f = getFunction(5);
Here a call to getFunction creates a closure containing the member closureMember, returns an anonymous function referencing this closure, and assigns it to the variable f. If I invoke the anonymous function, its code will be executed and the member closureMember in the closure will be actually accessed.
JavaScript allows me to invoke the method toString on an anonymous function that returns the textual representation of its code. In this case, the representation will contain the name of closureMember without giving any access to the actual variable (note that it can exists in multiple instances if getFunction was invoked multiple times).
Question:
Does JavaScript provide any reflection capabilities that would allow to analyze/modify the structure and content of closures associated with function instances at runtime?
I'm not sure that it's exactly what you want but the next code works fine.
function getFunction(x) {
var closureMember = x;
return function() {
return closureMember * 2;
};
}
function changeClosure(x, closure){
var closureMember = x;
return eval("(" + closure.toString() + ")");
}
var f = getFunction(5);
var g = changeClosure(42, f);
g();
I have come across this javascript code.
var digit_name = function() {
var names = ['zero', 'one','two'];
return function(n) {
return names[n];
};
}();
alert(digit_name(1));
The output is one. I understand that the inner function is being assigned to the variable digit_name. What is the need for adding parentheses in the 6th line after the code of outer function. Can anyone tell what exactly is going on?
The added parentheses makes the outer function execute, if you omit it it will assign outer function to your digit_name instead of the inner function.
The ending () you see make that outer function execute immediately. So digit_name ends up storing the resulting inner function, as opposed to a pointer to the outer function.
For more information see: What is the purpose of a self executing function in javascript?
Let's give some names to these functions to better understand what's going on:
var digit_name = function outer() {
var names = ['zero', 'one','two'];
return function inner(n) {
return names[n];
};
}();
alert(digit_name(1));
So, there are two functions at play here: inner and outer. You're defining a function called outer, whose purpose is to create a closure scope capturing the names array, and defining and returning another function that has access to this closure. The parentheses at line 6 mean call the function, so the value that gets assigned to the digit_names variable isn't the outer function, but the inner one.
var digit_name = function() {...}; => digit_name is a function
var digit_name = function() {...}(); => digit_name is an object returned by the function
var digit_name = function() { // Create outer function
var names = ['zero', 'one','two']; // Define names array, this is done when the outer function is ran
return function(n) { // Return the new inner function, which gets assigned to digit_name
return names[n];
};
}(); // Execute the outer function once, so that the return value (the inner function) gets assigned to digit_name
There are two very quick processes here.
If we were to write this:
function makeDigitReader () { var names; return function (n) { return names[n]; }; }
var myDigitReader = makeDigitReader();
You would correctly guess that myDigitReader would be given the inner function.
What they're doing is skipping a step.
By adding the parentheses, what they're doing is firing the function the instant that it's defined.
So you're getting this happening:
var myDigitReader = function () {
var names = [...];
return function (n) { return names[n]; };
};
myDigitReader = myDigitReader();
See what's happened?
You've returned the inner function as the new value to what used to be the outer function.
So the outer function doesn't exist anymore, but the inner function still has access to the names array.
You can return an object instead of a function, as well.
And those object properties/functions would have access to what was initially inside of the function, as well.
Normally, you will either see these immediately-invoking functions wrapped in parentheses var myClosure = (function() { return {}; }());.
If you intend to run one without assigning its return to a value, then you need to put it in parentheses, or add some sort of operand to the front of it, to make the compiler evaluate it.
!function () { doStuffImmediately(); }(); // does stuff right away
function () { doStuffImmediately(); }(); // ***ERROR*** it's an unnamed function
Hope that answers all of the questions you might have.
It is possible to access ther oute scope of a function?
I will explain better.
I've a function, from which I want to acccess its calling function scope.
function called() {
// i want to access the calling outer function scope
}
function calling() {
called();
}
obviusly called() function could be called by a lot of calling functions, and called() has to know time to time which function has called him,` and access its scope variables and functions.
No, that isn't possible.
To access a variable from two functions you need to either:
Declare it in a shared scope
var the_variable;
function called() {
// i want to access the calling outer function scope
}
function calling() {
called();
}
Pass it as an argument
function called(passed_variable) {
return passed_variable;
}
function calling() {
var some_variable;
some_variable = called(some_variable);
}
You should pass any relevant information into called() as parameters:
function called(x, y, z) {
}
function calling() {
var x = getX();
var y = computeY();
var z = retrieveZ();
called(x, y, z);
}
If you expect called to do different things, and receive different contextual information, depending on who calls it, you should probably make it multiple separate functions.
function called(outterScope) {
// outterScope is what you want
x = outterScope.declaredVariable;
outterScope.declaredFunction();
}
function calling() {
this.declaredVariable = 0;
this.declaredFunction = function() { // do something };
var _self = this;
called(_self);
}
No,
if you need to use variables from scope of calling code block (example function)
you have to pass them in arguments
or you can create object and access properties in Object scope (via this.param_name)
Depending on what you want to do, there might be better ways to do it, but if absoultely have to resort to it, you may find that out via Function.caller:
function myFunc() {
if (myFunc.caller == null) {
return ("The function was called from the top!");
} else
return ("This function's caller was " + myFunc.caller);
}
Do note that its not part of the standards, even though some major browsers and IE7 support it.
Also, you cannot access the caller functions scope or variables. Its usability is limited to finding out who called you (helpful for logging or tracing).