I know the title sounds convoluted, but to keep things dynamic there is a purpose for this rest assured ;)
Examples (note that these example codes are assumed to be within an outer eval)
//Ex1 this works
eval('function test (){}');
test();
//Ex2 this doesn't work (myfunction definition is written below)
myfunction();
test(); //I get an error
If I defined myfunction globally (outside of the outer eval) I get this error: object is not a function
If I defined myfunction within the outer eval I get this error: object is not a function
//myfunction definition
function myfunction () {eval('function test (){}');}
Question is: how do I expand the scope of a function definition to just outside of the function it was defined within? I know about making an eval global (see alternate myfunction below), but that seems like overkill, I just want to increase the scope to the outer eval is all. Is this possible?
Update:
The examples only define one function to keep is simple, but I wish expand it so that myfunction defines many functions, and what functions it defines is dynamic depending on other factors. Also I wish to retain the function names as well as the definitions. I may end up just putting the contents of myfunction into the outer eval if I can't find a solution other than making eval call globally, then I have to copy over the contents to everyplace that uses it.
//making eval global works, but I had hoped to just upscope to the calling eval
function myfunction(){var globaleval=eval;globaleval('function test(){}');}
Below has been edited since the initial question:
Maybe you could make a var in outer eval, have myfunction return the address of the function definition to that var. However, I wish to retain the function names as well as the definitions.
OK, so I am assuming you actually mean you want to control the scope in which eval uses...
Why not
eval.call(context, 'function test(){}');
example
eval.call(window, 'function test(){}');
eval() does execute within the local scope but that isn't your problem.
First, ditch eval()!
Second, think clearly on what you want without eval(). Even better please update the question when you have that.
Since I can't understand the actual question here are some guesses:
1. Reference to a particular object
If you want a reference to this of a particular object and the current context isn't sufficient Then use something like this question to "bind" (included in ecma 5) your new function to this.
You'll still have reference to the local closure of course.
2. Function that has a specific closure
If you want to call a function whose scope is "further out" or different than your "current scope" then define "that function" in the scope you want it to have (the closure) but then use a reference to "that function" that inner scope has
e.g.
var test='outer';
var outer = function (){ alert(test);}
(function(){
var test='inner';
var inner = function(){
alert(outer());
}
inner();
})()
You'll note that inner() returns "outer" in this example
in your second example function test() doesn't exists, because it's not defined yet )))
Related
I run into a bit of confusion regarding scoping with respect to where a callback is defined.
function test(){
var b = 3
var fun = function(){
var printingFunction = function(){
console.log(b)
}
printingFunction()
}
return fun
}
test()() //prints 3, as expected because of closures
However, the following doesnt work
function test(){
var b = 3
var fun = function(cb){
cb()
}
return fun
}
test()(function(){console.log(b)}) //b is not defined
I would expect that since the function is passed as an argument and has not been defined before, its definition takes place inside 'fun' and therefore it would have access to b. Instead, it looks a lot like the function is first defined in the scope where its passed and THEN passed as an argument. Any ideas/pointers?
EDIT: Some extra pointers.
someFunction("a")
We couldn't possibly claim that "a" is a definition. What happens here implicitly is that "a" is assigned to a variable named by the argument name so var argumentNameInDefintion = "a". This happens in the body of someFunction.
Similarly we cant claim {} is a definition in : someFunction({}). So why would:
someFunction(function(){})
decide that function(){} is a definition is beyond me. Had it been
var a = function(){}
someFunction(a)
everything would make perfect sense. Maybe its just how the language works.
Scoping in JavaScript is lexical. If you look at your examples, you can see that where printingFunction is defined, lexically (e.g., in the source text) b is declared in a containing scope. But in your second example, it isn't. That's why b can't be resolved in your second example but can in your first.
The way it works is that when a function is created, it has a reference to a conceptual object containing the variables and such in the scope in which it's created (which has a fancy name: "Lexical Environment object"); and that object has a reference to the one that contains it. When looking up a variable reference, the JavaScript engine looks at the current lexical environment object and, if it finds the variable, uses it; otherwise, it looks to the previous one in the chain, and so on up to the global one.
More details can be found:
In this SO question's answers
In this post on my anemic little blog
The issue stems from me not understanding that function(){} on its own is a definition and so is "a" and {}. Since these are definitions then the definition scope of the function passed is appropriately placed where it is and the world makes sense again.
In first case, it is forming a closure and has access to the variable "b" but in second case it does not form a closure at all. If you put a debugger just before the cb() inside the function, you will notice that there is no closure formed and the reason of that being the callback function is suplied to the function as an argument and it becomes local to that function which does not have any knowledge of the variable b.
Think of it as two different functions, one in which it has a local variable "b" and in other no local variable but we are trying to access it which throws the reference error.
I have code like this :
(function() {
$(document).ready(function() {
//event handlers
$('.project-delete').on('click', function() {
deleteProject($(this));
});
$('.keyword-delete').on('click', function() {
deleteKeyword($(this));
});
this.deleteKeyword = function(model) {
}
}).call(this);
I am curious if this is a good approach since I was learning JS recently and as far as I understand this function will have global scope, doesn't it ? since .call(this) is passing window object to this closure then I think it is not the best option ? Is there something I am missing ? Does changing .call(this) to just () change anything ?
EDIT:So is it OK to just pass window object to that closure ? Wouldn't it better to pass just a empty object or jQuery object ?
Assuming this function is defined in the global scope, the deleteKeyword function will have also have global scope since this in the context of the parent function is basically window (which has been passed in as this from outside; in the global scope this === window).
If you change .call(this) to just (), this is still window inside the function. This is because when you call a function via a simple function-call, this is set to the global object, which is window.
If you want a different value for this, you will need to pass in something else via .call or .apply.
For more information about the behavior of this, take a look here.
"as far as I understand this function will have global scope, doesn't it?"
"Scope" is about what variables a function has access to (i.e., its own local variables, plus locals declared in any functions that it might be nested inside, plus global variables), and that has nothing to do with the value of this. Scope depends on where the function declaration is, but this depends on how the function is called.
"since .call(this) is passing window object to this closure"
We can't tell that just from the code shown. Presumably you mean that that block of code is not nested inside some other function, so then yes, this would be window. But if that code was ever pasted inside some other function then that this might have some other value depending on how that other function was called.
"Does changing .call(this) to just () change anything?"
If you use just () that will mean that inside the function this will be window. Whether that changes anything depends on whether the this in .call(this) was window in the first place - as I already mentioned above, if that block were nested inside some other function this could be something else. Having said that, for the code shown if this was anything other than window I think your code would break. Because you declare a function like this:
this.deleteKeyword = function(model) {...}
...and then inside the second click handler you call what I assume is meant to be the same function without using this:
deleteKeyword($(this));
The only way that will work is if this is window and the deleteKeyword() function is thus global. If this were any other object the function would be a property of that other object and thus not accessible directly as deleteKeyword(). But unless you specifically want deleteKeyword() to be accessible from other code not shown there is no reason to create it as a property of this at all. Just declare it with var:
var deleteKeyword = function(...
...and then it will be accessible only inside that function and the ones nested in it such as your click handler. And the .call() at the end of your function would be redundant since the function wouldn't ever actually use this.
"so isn't it a better option to apply jQuery object (or maybe just empty object) to it to increase performance? Wouldn't it increase performance if this would point to local scope? Since window object is very slow."
Well as I already said, "scope" and the value of this are unrelated concepts. I'm not sure why you are worrying about performance for that code. But if you were to apply jQuery or an empty object with .call(jQuery) or .call({}) the code would not work as explained above.
"[JavaScript functions] internally store any variables they may refer to that are defined in their enclosing scopes."
How can I determine what that set of variables is?
For example, David Herman in Effective JavaScript gives this function (and closure):
function sandwichMaker() {
var magicIngredient = "peanut butter";
function make(filling) {
return magicIngredient + " and " + filling;
}
return make;
}
var f = sandwichMaker();
document.writeln("<p>" + f("jelly") + "</p>");
document.writeln("<p>" + f("bananas") + "</p>");
document.writeln("<p>" + f("marshmallows") + "</p>");
Sure, magicIngredient is a variable accessible to make(), but what else is? What if sandwichMaker were itself within a function? And then there are the globals. What is the function looking at when it looks for relevant values within the current scope?
What if sandwichMaker were itself within a function? And then there are the globals.
Yes, all the variables from parent functions are accessible (if they are not shadowed). And the highest-scoped function inherits from the global scope then.
What is the function looking at when it looks for relevant values within the current scope?
You can inspect that with a debugger. Insert a debugger; statement in make, and then execute it and have a look into your devtools. You will see something like this:
Scope Chain
0. make (currently executed):
this: (+)Window
arguments: (+)Arguments
filling "jelly"
1. sandwichMaker:
arguments: (+)Arguments
magicIngredient: "peanut butter"
make: (+)Function
Global
AnonXMLHttpRequest: …
ApplicationCache: …
Array: …
…
Also have a look at this great article: http://dmitrysoshnikov.com/ecmascript/es5-chapter-3-2-lexical-environments-ecmascript-implementation/
Example view at Chrome Devtools:
(from www.briangrinstead.com):
JavaScript uses function scope. This is pretty simple to understand - anything declared in a function has scope to that function as well as any higher scopes.
A closure can be thought of as two things being combined together: a particular scope, and a particular point in time (when the function was created).
Sure, magicIngredient is a variable accessible to make(), but what
else is?
Anything that was accessible to the scope of make at the time it was created. This includes all variables in the make function as well as any higher scopes. The scope of make is said to be closed-over the scope that existed at the point in time it was created, always giving it access to magicIngredient.
What if sandwichMaker were itself within a function?
Then make would have access to that scope (as it existed at the time make was created) as well.
And then there are the globals. What is the function looking at when it looks
for relevant values within the current scope?
The interpreter will search the currently executing scope for any referenced variables. If it can't find them, it will look in the next higher scope. It will continue looking higher and higher until it finds the variable or runs out of scopes (the global scope is the highest, aka the window object for javascript running in a browser).
A related concept is shadowing - two variables can have the same name in parent/child scopes, the child is said to "shadow" the parent because it will take precedence. Note this is a bad practice.
The easiest way to understand how closures and scoping works is to understand a simple factory pattern, such as this one. When the inner function is created and returned, it is bound to that scope at that point in time and will continue to alert the proper values even after the values no longer exist.
Hope this helped - lots of questions stuffed into one question :)
Suppose above function sandwichMaker() there was a variable defined...
var something = 'something';
function sandwichMaker () {
...
You can access something from within sandwichMaker() AND from within make().
The outer variables are accessible from within the functions. If you were to set var something = 'something else' within make(), then you would be effectively hiding the outer var something while within the make() function itself. However, you can just set something = 'something else', and the value will have changed at all scopes. It only hides the value if you declare that variable again.
I now know this works:
function outerfunction(arg1, arg2, arg3) {
var others;
//Some code
innerFunction();
function innerFunction() {
//do some stuff
//I have access to the args and vars of the outerFunction also I can limit the scope of vars in the innerFunction..!
}
//Also
$.ajax({
success : secondInnerFunction;
});
function secondInnerFunction() {
// Has all the same benefits!
}
}
outerFunction();
So, I am not doing a 'new' on the outerFunction, but I am using it as an object! How correct is this, semantically?
There doesn't appear to be anything wrong with what you're doing. new is used to construct a new object from a function that is intended as a constructor function. Without new, no object is created; the function just executes and returns the result.
I assume you're confused about the closure, and how the functions and other variables belonging to the function scope are kept alive after the function exits. If that's the case, I suggest you take a look at the jibbering JavaScript FAQ.
You are not using the outer function as an object. You are using it to provide a closure. The border line is, admittedly, thin, but in this case, you are far away from objects, since you do not pass around any kind of handle to some more generic code invoking methods, all you do is limiting the scope of some variables to the code that needs to be able to see them.
JFTR, there is really no need to give the outer function a name. Just invoke it:
(function() { // just for variable scoping
var others;
...
})()
I do this sort of thing all the time. Yes - javascript blurs the boundary between objects and functions somewhat. Or perhaps, more correctly, a javascript function is just an object that is callable. You would only really use the 'new' prefix if you wanted to have multiple instances of the function. My only suggestion here is that its usually considered good practice to call a function after you've declared it (you are calling the innerFunction before it has been declared) - although that could be considered nit-picking.
This is a valid example.
Functions in JavaScript are first order objects. They can be passed as an argument, returned from a function or even set to a variable. Therefore they are called 'lambda'.
So when you are directly using this function (without new keyword) you are directly dealing with the function as an object. When u are using new keyword, you are dealing with an object instance of the function.
I'm trying to wrap my head around closures (there's a joke in there somewhere) and I ran across this:
(function () { /* do cool stuff */ })();
How does this work? What's the purpose of putting the function in parens? Why the empty parens afterwards?
The point of this is that any variables declared in the cool stuff will not be created in global namespace. Any function in javascript will create such a scope. Suppose you have some javascript you want to run. If you do this:
var b = 1;
// stuff using b
And some other code uses b, it will get your left over value. (Or, even worse, if some other code sets b before your code runs, then tries to get its old value later, you'd have changed it in the meantime.)
On the other hand, if you have this code, which declares and then calls the a function:
function a() {
var b = 1;
}
a();
And some other code later on uses b, it will not see your values, since b is local to the function. The problem with this, of course, is that you're still making a global name - "a", in this case. So, we want a function with no name - this is why you get the code you described. It declares a function with no name, and then calls it.
Unfortunately, you can't just say:
function() { ... }()
because this will be parsed as a function declaration statement, and then a syntax error. By wrapping the function declaration in parenthesis, you get a function expression, which can then be called. You call it like any other function expression (like a, above), using the second set of parens. For example, if the function took arguments, you'd pass them there:
(function(a) { ... })(1)
That creates a function, calls it, and discards it.
It might be clearer if you look at it like this:
var throwaway = function(){
// do cool stuff
};
throwaway();
This is done to create a private namespace. Code in the function can have functions and variables without worrying about conflicting with other code loaded in the page.
i just came across this post recently. This type of function definition & call is called self-invoking functions.
(function(){ //code })();
The code inside the function will be executed immediately upon its definition.
That construct means declare an anonymous function and run it immediately. The reason you put your code inside a function body is because the variables you define inside it remain local to the function and not as global variables. However, they will still be visible to the closures defined inside this function.
The parens around the function make it clear that the function is an expression. The parens after are the call to the function.
Notice that the function does not have a name.
One closures approach is to pass variables to the function:
(function($, var_1, var_2) {
// use JQuery, var_1 and var_2 as local variables
})($, var_1, var_2);
Putting the function declaration inside parens creates an expression which evaluates to the anonymous function within. Therefore, the first parenthetical evaluates to a function.
The "empty parens" at the end invoke the defined function, so "//do cool stuff" executes immediately.
This is a way to execute code on-the-fly while also keeping variables out of the global scope.
What is illustrated here, however, has nothing to do with closures - at least not directly. Closures are about maintaining a lexical scope after a parent function has already exited.