In javascript, What is the difference between function declaration and function expression in terms of scope? function declaration means we are polluting the global space. Is it the same case with function expression?
Function declaration
function sum(){
// logic goes here
}
Function expression
var sum = function(){}
Both are equivalent in terms of scope. A function declared inside another function will not be global. The difference is that you can use a declared function at any time (because it's hoisted before any code is run), a function assigned to a variable as an expression only after you have assigned it.
(function () {
bar(); // works
function bar() { } // is not global
foo(); // doesn't work
var foo = function () { };
})();
As far as polluting the enclosing scope goes, both are equivalent. Note that it is not necessarily the global scope - it is the scope in which the function is declared (local functions are permitted within other functions). In your example, both methods introduce a variable (function object) named sum into the local scope.
Related
The var keyword in javascript causes a variable to be stored in the local scope. Without var variables belong to the global scope. What about functions? It's clear what happens when functions are declared like variables
var foo = function() {...}
but what scope does
function foo() {...}
belong to?
EDIT:
I realized I didn't ask quite the right question so as a follow up. In the outer most nesting is there a difference between the above two declarations and the following declaration?
foo = function() {...}
It belongs to the current scope, always. For example:
// global scope
// foo is a global function
function foo() {
// bar is local to foo
function bar() {
}
}
Regarding your second question, this:
foo = function() {...}
is an anonymous function expression assigned to a global variable (unless you're running is strict mode, then foo would be undefined). The difference between that and function foo() {} is that the latter is a function declaration (versus a variable declaration, which is assigned an anonymous function expression).
You might be interested in this excellent article about function declarations and function expressions: Named function expressions demystified.
Function declarations are always local to the current scope, like a variable declared with the var keyword.
However, the difference is that if they are declared (instead of assigned to a variable) their definition is hoisted, so they will be usable everywhere in the scope even if the declaration comes in the end of the code. See also var functionName = function() {} vs function functionName() {}.
Noteworthy distinction taking implicit globals into account:
var foo = function() {
// Variables
var myVar1 = 42; // Local variable
myVar2 = 69; // Implicit global (no 'var')
// Functional Expressions
var myFn1 = function() { ... } // Local
myFn2 = function() { ... } // Implicit global
function sayHi() {
// I am a function declaration. Always local.
}
}
Hopefully that clarifies a little. Implicit globals are defined if you forget a var before your assignment. Its a dangerous hazard that applies to variable declarations and functional expressions.
Your first example (var foo = function() {...}) is called an anonymous function. It is dynamically declared at runtime, and doesn't follow the same rules as a normal function, but follows the rules of variables.
According to hoisting definition:
Hoisting is a JavaScript mechanism where variables and function
declarations are moved to the top of their scope before code execution
Why do function declarations get hoisted and function expressions don't?
As per MDN,
Conceptually, for example, a strict definition of hoisting suggests that variable and function declarations are physically moved to the top of your code, but this is not in fact what happens. Instead, the variable and function declarations are put into memory during the compile phase, but stay exactly where you typed them in your code.
As you see, in a function expression, actual function is a value assigned to a named variable. So this named variable is hoisted. Even if you have a named function assigned, it still will not be hoisted as it is not a declaration and will be created later.
Sample:
function test() {
console.log(fn, foo);
var fn = function foo() {}
}
test();
I know I could just pass it as a parameter but as an effort to understand JS further, is there anything like this:
function logIt() {
console.log(x)
}
[0,1,2].forEach(x => logIt())
// x is not defined
Actually no. Function tries to find the variables in the scope and the above scopes where it was declared. In your case logIt is declared in the global scope and it tries to find x there, but your x is defined in the function scope which is passed to the forEach. In other words logIt doesn't look for its variable in the x => logIt() scope.
// Global scope, Look here, this is the scope where `logIt` was declared
function logIt() {
// Look here, this is my scope
console.log(x)
}
[0,1,2].forEach(x => {
// Does not look here, it is not the scope where `logIt` was defined and not the global scope
logIt();
})
Scope access has to do with the scope in which the function is defined, not the scope in which it is used. Since x does not exist in the scope in which logIt() is defined, it is unavailable inside the function unless it is passed in via an argument.
Not really, no. A function can't reach out and access variables in the scope that called it.* Which is a Good Thing™. :-)
You could define a variable that both logIt and the anonymous forEach callback have access to, set the value of that variable in the callback, and use it in logIt:
// DON'T DO THIS, KEEP READING
let x;
function logIt() {
console.log(x)
}
[0,1,2].forEach(_x => {
x = _x;
logIt();
})
...but that would be a Bad Thing™ in most cases. We have function arguments for a reason. :-)
* (It can access variables in the execution context for the scope where and when it was created [and the contexts containing that context], but that's different.)
From the Mozilla Doc https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures :
function makeFunc() {
var name = "Mozilla";
function displayName() {
alert(name);
}
return displayName;
}
var myFunc = makeFunc();
myFunc();
Isn't displayName the actual closure as it closes upon the scope of its outer function makeFunc for later use? Mozilla says makeFunc is the closure:
The solution to this puzzle is that myFunc has become a closure. A closure is a special kind of object that combines two things: a function, and the environment in which that function was created.
I remember reading different definitions..
Also Mozilla contradict themselves regarding the following code they say:
function init() {
var name = "Mozilla"; // name is a local variable created by init
function displayName() { // displayName() is the inner function, a closure
alert (name); // displayName() uses variable declared in the parent function
}
displayName();
}
init();
init() creates a local variable name and then a function called displayName() displayName() is the inner function (a closure) — it is defined inside init(), and only available within the body of that function.
So in summary they say both the inner function and the outer function have become a closure..
SORRY QUESTION CLSOED. I misread 'myFunc' as 'makeFunc' -_-
I think you misread the docs - myFunc is the closure, bnot makeFunc, as you thought it was.:
init() creates a local variable name and then a function called displayName(). displayName() is the inner function (a closure) — it is defined inside init(), and only available within the body of that function . Unlike init(), displayName() has no local variables of its own, and instead reuses the variable name declared in the parent function.
Just replace init with makeFunc and apply the quote above to your code. displayName is what is returned, and thus exposed. It's a function object with access to the var name.
So yes, displayName is a closure, and it's a closure that is created and returned by makeFunc.
When you assign this returned closure to a variable, then that variable is that closure. In your case myFunc is assigned the return value of createFunc, meanting it is assigned an instance of a function, called displayName inside itself, that has access to a var name.
The next time createFunc is invoked, a new name var will be created, and a new displayName function is created. If you assign that to another var, then you have 2 closures that, even though they use the same variable names internally, and they were both returned by the same function, are 2 separate closures.
In JS, functions are first-class objects (meaning they can be passed around and assigned like any other value). This means that:
var foo = function (bar) //assign function to variable foo
{
return function()//this function will return a function
{
bar();//that invokes bar, an argument passed to the outer function
alert('bar was invoked');
};
}
var closure = foo(function(){ alert('test');});//pass function to foo
//returns the inner function, that invokes the function we just passed:
closure();//will alert "test", and then "bar was invoked"
var closure2 = foo(function(){ alert('a new closure');});
closure2();//alerts "a new closure" and "bar was invoked"
closure();// still alerts the same
From Wikipedia:
In programming languages, a closure (also lexical closure or function closure) is a function or reference to a function together with a referencing environment
So displayName is the function and makeFunc is the source of the referencing environment, and together they make the closure.
I really hope this isn't a duplicate.
function a(){ b(); } // function a calls function b; but there's no function b in the global scope...
(function(){
// the purpose was to declare it later because it may collide with user-defined functions
var b = function(){ console.log('I am function b()'); };
a(); // doesn't work, obviously
a.call(this); // also doesn't work
a.apply(this, []); // doesn't work either
// neither works
var scope = { 'b': function(){ return b.apply(this,arguments); } };
with(scope){
a.call(scope);
}
// ... what works then?
}());
Simply put, function a() declared globally calls function b(). Function b() is not declared before a() and will not be part of the same scope.
So:
We cannot modify function a(), nor its location where is defined
We cannot declare b() in the same scope with a()
We also cannot var a = eval(a().toString()) or any likewise cheats
With pure scope handling, is this possible? And if it it's not, what else can we do?
Just trying to learn some JavaScript here that's all.
You can't do it. Variables local to a scope cannot be accessed outside that scope, that's the whole point of scoping. If you want to make the b() function visible outside the anonymous function, you need to assign it to an outer variable.
When you create a function object, it wraps all the enclosing functions and forms the closure. Later, whenever the object being used is not found in the local scope, the enclosing function objects will be searched.
In your case, a is declared in the global scope and there are no enclosing functions. When you invoke a from the IIFE, b will be searched within a itself and its enclosing functions and finally in the global scope, which is not found anywhere in that list of scopes. That is why it fails with
ReferenceError: b is not defined
Note: The important thing to be noted here is, when you invoke a function, the scope in which the function was defined will be searched, not where it is invoked from.
So, the answer is NO. Its not possible to do what you are trying to do.