JavaScript: I need create a function within a specific scope.
The function to be created, is generated dynamically by a previous process of code generation. And the scope for the definition of this function may also change.
Look this example:
var createFnInOtherScope = function() {
console.debug('createFnInOtherScope: Who I am', this);
//This code can not be modified because it's dynamically generated
function MyFunction() {
console.debug('MyFunction');
}
}
var obInitial = {
createFn: function() {
console.debug('createFn: Who I am', this);
createFnInOtherScope.call(window);
}
}
obInitial.createFn();
//ReferenceError: MyFunction is not defined
window.MyFunction();
How I can do this?
Thanks.
If I understand you correctly, what you're asking is impossible.
Scope in Javascript is a lexical construct, meaning that what's in scope is defined by its physical location (at parse time) in the source file with respect to any enclosing functions.
You can't retrospectively add something into a scope once that scope has (lexically) been closed off.
Function scope is defined at parse time. You can create a function and make it visible as a window property:
function outer() {
function inner() {
console.log("hello world");
}
window.inner = inner;
}
window.inner(); // hello world
But that does not alter the scope of the "inner" function. It's visible and callable via the global object, but the function is unalterably in the scope of that "outer" function.
Just define this function in this context:
var createFnInOtherScope = function() {
this.MyFunction = function() {
console.debug('MyFunction');
};
};
DEMO: http://jsfiddle.net/Ur6vF/
Related
This question already has answers here:
What is the scope of variables in JavaScript?
(27 answers)
Closed 8 years ago.
Here is the jsfiddle.
Code:
$(function(){
f1();//OK
f2();//OK
function f1(){
console.log("1");
}
});
function f2(){
console.log("2");
}
f2();//OK
f1();//NO!!!
As you can see, the f1() is not executed from globe scope(or outside jquery scope). Could some one tell me why?
Functions declared within other functions are ONLY available within the function in which they are declared. They are like local variables in that regard. They are private to the scope in which they are declared and there is no way to access them from the outside.
If you want it available in a higher scope, then declare the function in the higher scope or assign it to a higher scope and then you can call it from both places.
$(function(){
f1();//OK
f2();//OK
});
function f1(){
console.log("1");
}
function f2(){
console.log("2");
}
f2();//OK
f1();//OK
It's also possible to do this (manually assigning a function into the global scope):
$(function(){
// assign function into the top level scope
window.f1 = function(){
console.log("1");
}
f1();//OK
f2();//OK
});
function f2(){
console.log("2");
}
f2();//OK
f1();//OK - only after document is ready and window.f1 has been assigned
This is so-called closure!
JS function has its own scope: variables defined inside a function cannot be visited outside it. If you want to do so, you must have a reference to it from the outer scope.
var globarF1;
$(function(){
f1();//OK
f2();//OK
function f1(){
console.log("1");
}
globarF1 = f1;
});
globarF1();// now it's ok
Here's a more interesting example:
function outer() {
var asdf = 1;
return function() {
return asdf;
}
}
asdf; // Error: asdf is not defined
var qwer = outer();
qwer(); // 1
Notice that outer() just returns an amounymous function, qwer() actually executes the amounymous function, and this is the power of closure: function outer's execution scope is not destroyed even if it has returned, because there is a reference to its local variable from outside, and you can visit the variable asdf inside it in this way.
I have the following working JS script in one of the sites I'm working on. I'm wondering why the variables 'countryEl' and 'zipEl' are accessible from within the function passed to Event.observe. Can anybody explain?
Thanks in advance!
<script type="text/javascript">
//<![CDATA[
document.observe("dom:loaded", function() {
var form = $('shipping-zip-form');
var countryEl = form.down('#country');
var zipEl = form.down('#postcode');
Event.observe(countryEl, 'change', function () {
var selectedValue = $(countryEl).getValue();
if (selectedValue == 'US') {
zipEl.addClassName('validate-zip-us');
}
else {
zipEl.removeClassName('validate-zip-us');
}
});
});
//]]>
</script>
The following code snippet demonstrates that the variable "v" is only accessible from the context in which it was defined, that is to say the context of the "outer" function. Hence, functions defined inside this context can access "v" as well.
function outer () {
var v = 'hello!';
inner();
console.log('from outer: ' + v);
function inner () {
console.log('from inner: ' + v);
}
}
try {
outer();
console.log('from global: ' + v);
} catch (e) {
console.log(e.message);
}
More: http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html.
###Additional note
The combination of the "inner" function and the environment is called a "closure". I'm still a bit confused regarding the exact definition. Some might use this term to designate the "inner" function itself, but it sounds more like a misuse. Here is what MDN says:
Closures are functions that refer to independent (free) variables. In other words, the function defined in the closure 'remembers' the environment in which it was created. (MDN)
A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. (MDN)
If it did not, life would be so much harder. Apparently the private vars in document.observe are still local inside the Event.observe possibly passed on by some jugglery of the api. But would you rather not have it that way? How would that be of help I cannot imagine.
In the "JavaScript Patterns" book by Stoyan Stefanov, there's a part about Self-Defining Function.
var scareMe = function(){
console.log("Boo!");
scareMe = function(){
console.log("Double Boo!");
}
}
scareMe();//==>Boo!
scareMe();//==>Double Boo!
It works as I expected. But I modify the scareMe function as following:
function scareMe(){
console.log("Boo!");
function scareMe(){
console.log("Double Boo!");
}
}
scareMe();//==>Boo!
scareMe();//==>Boo!
Problem:
what's the difference between them?
In the second case, why the output is not "Double Boo!", but "Boo!"
The first scareMe function when invoked overwrite its own behavior by creating another function scareMe inside it, which overwrites the one in the upper scope, so the definition of original scareMe changes, i have see this approach been used if you want to do a first time set up in an application and want to change its behavior all over right after setting it up.
If you had defined:
var scareMe = function(){
console.log("Boo!");
var scareMe = function(){ //define it with var
console.log("Double boo!");
}
}
scareMe();//==>Boo!
scareMe();//==>Boo! //you will see the behavior as that of the second one.
Also one practical implementation of a one time setup:
var scareMe = function(){
console.log("Boo!");
//I have done my job now. I am no longer needed.
scareMe = undefined;
}
scareMe();//==>Boo!
scareMe();//==> oops error
Second Case you are creating a new function with the name scareMe whose scope is only within the function, it doesn't overwrite itself.
Try this one for instance:
function scareMe(){
console.log("Boo!");
function scareMe(){
console.log("Double bool!");
}
scareMe(); //Now this invokes the once defined inside the scope of this function itself.
}
scareMe();//==>Boo! and Double bool!
In your first approch, scareMe is a global variable (in your context). When in the "double boo", you change the value of that global variable, so it works.
In the second approch, the inner scareMe is a local variable and it won't change value of the global one.
So it's about the variable scope.
Except for hoisting and debuggability, you can consider:
function f(/* ... */) { /* ... */ }
To be equivalent to:
var f = function(/* ... */) { /* ... */ };
If we translate your second code sample to use this second form, we get:
var scareMe = function() {
console.log("Boo!");
var scareMe = function() {
console.log("Double bool!");
};
};
Note that this is not the same as your first snippet; the inner function definition has a var on it. With the inner var, it creates a new variable called scareMe that shadows the outer one.
In the module pattern in JavaScript "Immediately-Invoked Function Expressions" (also known as self-executing anonymous functions) are used as self executing functions that return an object.
How can a self-executing function hide private variables and only expose the returned object. Why does this not happen with a normal JavaScript function?
So in the following mini module, why could we not achieve the same concept of encapsulation without the enclosing ()()?
var Module = (function () {
var privateVariable = "foo",
privateMethod = function () {
alert('private method');
};
return {
PublicMethod: function () {
alert(privateVariable);
privateMethod();
}
};
})();
How can a self-executing function hide private variables and only expose the returned object. Why does this not happen with a normal JavaScript function?
It does happen with normal JavaScript functions.
function MakeModule() {
var privateVariable = "foo",
privateMethod = function () {
alert('private method');
};
return {
PublicMethod: function () {
alert(privateVariable);
privateMethod();
}
};
}
var Module = MakeModule();
would work just fine.
The only difference is that the anonymous function introduces one less global variable and allows for itself to be garbage collected while MakeModule can't be collected unless explicitly deleted by the author.
The privateness is because of closures. The "var privateVariable" is closed over by "PublicMethod", so only that function can access the variable because only it has it in its closure. It cannot be referenced by anything else and is "private"
This happens not only in "Immediately-Invoked Function Expressions" but also in normal function calls. It is just a way to immediately create the closure when defining the module instead of doing it later when you call the outer function.
Also see this post from Douglas Crockford himself: http://javascript.crockford.com/private.html
You can define a anonymous function via named function.
Example:
//factorial
(function(n){
var self = function(n){
//call self
return n > 0 ? (self(n-1) * n) : 1;
}
return self;
})()
Refering to How do JavaScript closures work?.
Closure is:
a closure is the local variables for a function — kept alive after the function has returned, or
a closure is a stack-frame which is not deallocated when the function returns (as if a 'stack-frame' were malloc'ed instead of being on the stack!).
Just want to confirm are the following consider closure?
1) Binding javascript function within a function.
var Books = {
init:function(){
$('#box').bind('click',function(){
console.log('click');
});
}
};
Books.init();
2) Declare a function within a function
function sayHello(name) {
var text = 'Hello ' + name;
var sayAlert = function() { alert(text); }
}
var hello = sayHello();
I still can't differentiate which is closure for some times, is that all function within function consider closure or only the one that keep the returned inner function as variable/reference. Example:
function sayHello(name) {
var text = 'Hello ' + name;
var sayAlert = function() { alert(text); }
**return sayAlert;**
}
1 isn't as no variables are actually referenced, 2 and 3 are.
In 2 and 3 the variable called text is closed off - referenced outside its lexical scope. In 1 nothing is.
crockford on closures :
What this means is that an inner function always has access to the
vars and parameters of its outer function, even after the outer
function has returned.
All of those are closures.
I'm not sure what your confusion is.