I thought one of the point of functions in javascript was to provide scope. Things defined in a function were only available inside the function.
function cat(name) {
talk = function() {
alert(" say meeow!" )
}
}
talk()
I would expect the above code to fall over because talk should not be visible. But it is, why?
It is because you didn't declare it with a var keyword.
If you don't use the var keyword, it will be in the global scope. If you do use var, it will be in the function scope:
function cat(name) {
//anonymous function assigned to the local variable talk
var talk = function() {
alert(" say meeow!" )
};
}
You can declare named functions without the var keyword, and they will still be in the local scope:
function cat(name) {
//local talk function
function talk() {
alert(" say meeow!" )
};
}
You haven't actually defined the variable in any scope. So it default to global scope.
function cat(name) {
var talk = function() { // <-- added var
alert(" say meeow!" )
}
}
talk() // fail
JavaScript allows you to use variables without defining them, this makes the programming language easier to learn and more flexible. I wouldn't recommend you make use of this feature though. Always define your variables.
inside of a function, you have to declare variables with "var" or they are declared globally. so you would do:
function cat(name) {
var talk = function() {
alert(" say meeow!" )
}
}
talk() // error: undefined
Related
Let us consider the workable code:
var storage = {};
(function() {
function internalMethod1() { ...; return; }
function internalMethod2() { ...; return; }
storage.storedMethod = internalMethod1;
})();
storage.storedMethod();
Is there any way to call internalMethod2, if it is not called in internalMethod1? In other words, can I access an anonymous closure from outside, if I have access only to one of its functions?
can I access an anonymous closure from outside?
No. Scopes are private in JS, and there's absolutely no way to access them from the outside (unless you use the engine's implementation-specific debugging APIā¦).
Variables (including functions) are only available in the same scope and its children. If you want to access their values outside of the scope, you're at the mercy of the function to expose them in some way (return, assign to global storage variable etc).
No, you cannot access a private, unreferenced scope after it has been executed. You would need to create another closure to create a reference to whatever private method you wanted to expose.
var storage = {};
(function() {
function internalMethod1() {
return {
internalPublic1: internalMethod2
};
}
function internalMethod2() {
console.log('hi');
}
storage.storedMethod = internalMethod1;
})();
var a = storage.storedMethod();
a.internalPublic1(); //'hi'
Try defining IIFE as variable , return reference to internalMethod2 from IIFE
var storage = {};
var method2 = (function() {
function internalMethod1() { console.log(1) };
function internalMethod2() { console.log(2) };
storage.storedMethod = internalMethod1;
return internalMethod2
})();
storage.storedMethod();
method2();
Still feel my understanding of Javascript closure is a little woolly at times and I would like to know if the code below represents closure in action...
function StateManager () {
var self = this;
this.state = null;
$(document).on("internal_StateManager_getState", function () {
return self.state;
});
$(document).on("internal_StateManager_setState", function (e, p) {
if ( p && p.state ) {
self.state = p.state
}
return self.state;
});
};
new StateManager();
alert( $(document).triggerHandler("internal_StateManager_setState", { "state": 88 }) );
Is it accurate to say that this demonstrates closure because the state and self variables are accessable via the events? Thanks for any input!
In the code in the question, the StateManager function does not create a closure, as it doesn't reference "free" variables from outside it's lexical scope.
However the jQuery callbacks are in fact closures, as they do reference the self variable which is defined outside the lexical scope of the callback functions.
A closure is, from MDN
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.
A simple example would be something like
function something() {
var test = "Hello Kitty"; // "test" is a local variable created in this scope
function otherFunc() { // this is an inner function, a closure
alert( test ); // uses variable declared in the parent function
}
}
That's about as simple as closure gets, it's just a function inside another function that uses variables outside it's lexical scope.
Another familiar example would be
$(document).ready(function() { // creates outer scope
var data = 'important stuff';
$('.elems').on('click', function() { // this is a closure
$(this).text( data ); // uses variable outside it's scope
});
});
I've wrapped all my functions around an immediately-invoked function expression as shown:
(function(){
"use strict";
function toggleComment(parentCommentID) {
$("form#" + parentCommentID).toggle();
}
function scrollBottom() {
window.scrollTo(0, document.body.scrollHeight);
}
})();
However, upon calling one of these functions through a link:
Reply
The Chrome console outputs Uncaught ReferenceError: toggleComment is not defined. Am I mistaken in thinking that an immediately-invoked function expression, as its name suggests, should be invoked immediately and therefore toggleComment should be called? Should I call the function differently?
The function toggleComment is not visible. It's enclosed in the ready function you're using; if you want to be able to call it like that (which is not recommended, in most cases), you have to hoist it outside of that function and make it globally accessible.
And this has nothing to do with strict. If you remove the strict line, this problem will still be the same.
The functions are no longer declared in the global scope. Try
window.toggleComment = function(parentCommentID) {
$("form#" + parentCommentID).toggle();
};
You have declared the functions inside a closure. They're outside of the scope of the HTML tag.
You could set an id to your <a> tag as well as publish your function to the global scope, so you can do this:
(function(){
"use strict";
var toggleComment = function(parentCommentID) {
$("form#" + parentCommentID).toggle();
}
function scrollBottom() {
window.scrollTo(0, document.body.scrollHeight);
}
document.getElementById("yourATagId").onclick(function() {
toggleComment(159);
});
window.toggleComment = toggleComment;
})();
Maybe you could benefit from this simple singleton pattern:
(function() {
var controller = {};
controller = new function() {
this.sampleProperty = "my property";
}
controller.yourFunction = function() {
var localVariable;
console.log("I can access " + this.property);
};
window.controller = controller;
})();
This way, controller will be known to your global scope.
I got a piece of code for javascript which I just do not understand:
function dmy(d) {
function pad2(n) {
return (n < 10) ? '0' + n : n;
}
return pad2(d.getUTCDate()) + '/' +
pad2(d.getUTCMonth() + 1) + '/' +
d.getUTCFullYear();
}
function outerFunc(base) {
var punc = "!";
//inner function
function returnString(ext) {
return base + ext + punc;
}
return returnString;
}
How can a function be defined within another function? Can we call pad2() from outside of my() function?
Please put some light on it. Thanks
Functions are another type of variable in JavaScript (with some nuances of course). Creating a function within another function changes the scope of the function in the same way it would change the scope of a variable. This is especially important for use with closures to reduce total global namespace pollution.
The functions defined within another function won't be accessible outside the function unless they have been attached to an object that is accessible outside the function:
function foo(doBar)
{
function bar()
{
console.log( 'bar' );
}
function baz()
{
console.log( 'baz' );
}
window.baz = baz;
if ( doBar ) bar();
}
In this example, the baz function will be available for use after the foo function has been run, as it's overridden window.baz. The bar function will not be available to any context other than scopes contained within the foo function.
as a different example:
function Fizz(qux)
{
this.buzz = function(){
console.log( qux );
};
}
The Fizz function is designed as a constructor so that, when run, it assigns a buzz function to the newly created object. That is, you'd use it like this:
const obj = new Fizz();
obj.buzz();
or more concisely (if you don't need to keep the object after calling buzz):
new Fizz().buzz();
It is called closure.
Basically, the function defined within other function is accessible only within this function. But may be passed as a result and then this result may be called.
It is a very powerful feature. You can see more explanation here:
javascript_closures_for_dummies.html mirror on Archive.org
function x() {}
is equivalent (or very similar) to
var x = function() {}
unless I'm mistaken.
So there is nothing funny going on.
Function-instantiation is allowed inside and outside of functions. Inside those functions, just like variables, the nested functions are local and therefore cannot be obtained from the outside scope.
function foo() {
function bar() {
return 1;
}
return bar();
}
foo manipulates bar within itself. bar cannot be touched from the outer scope unless it is defined in the outer scope.
So this will not work:
function foo() {
function bar() {
return 1;
}
}
bar(); // throws error: bar is not defined
When you declare a function within a function, the inner functions are only available in the scope in which they are declared, or in your case, the pad2 can only be called in the dmy scope.
All the variables existing in dmy are visible in pad2, but it doesn't happen the other way around :D
It's perfectly normal in JavaScript (and many languages) to have functions inside functions.
Take the time to learn the language, don't use it on the basis that it's similar to what you already know. I'd suggest watching Douglas Crockford's series of YUI presentations on JavaScript, with special focus on Act III: Function the Ultimate (link to video download, slides, and transcript)
function foo() {
function bar() {
return 1;
}
}
bar();
Will throw an error.
Since bar is defined inside foo, bar will only be accessible inside foo.
To use bar you need to run it inside foo.
function foo() {
function bar() {
return 1;
}
bar();
}
Nested functions can be the basis for writing a modular group of related functions, kind of halfway to full object-oriented programming (static classes only).
Here is an example of such a group of functions, in this case to convert a value to a JSON string or a JSON string to a value.
Notice how the inner functions are grouped into an Object inside an outer function, and how the Object is then stored into a group name. This is the only name directly visible from outside the group. To reach any contained function from outside, you just write the group name, a period, then the function name. To reach a contained function from inside, you can use the same notation, or 'this', a period, then the function name.
//--------------------------------------------------------------------//
// Module J:
// Convert from and to JSON strings
//--------------------------------------------------------------------//
const J=NewJ();
function NewJ()
{
const mod=
{
From:(str)=>
{
return JSON.parse(str);
}, // From
To:(val)=>
{
return JSON.stringify(val,null,3);
} // To
}; // mod
return mod;
} // NewJ
//--------------------------------------------------------------------//
// End Module J
//--------------------------------------------------------------------//
Here's a test:
console.log(J.To({A:'a'}));
Console output:
{
"A": "a"
}
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).