Can someone explain what is the difference between following two IIFE blocks:
a) (f1 = function(){console.log('IIFE Block1')})()
b) (var f1 = function(){console.log('IIFE Block2')})()
I understand that "b)" upon execution will throw error.
What is the use of defining the variable "f1" and what are its properties.
a only works outside of strict mode. f1 is being implicitly defined as a global variable and set to the value of your IIFE. If you try this in strict mode, an error will be thrown because f1 hasn't been explicitly declared with var, let, const, or as a function argument:
function quirks() {
(f1 = function() { return 'f1 IIFE'; })();
return f1;
}
console.log(quirks());
function strict() {
"use strict";
(f2 = function() { return 'f2 IIFE'; })();
return f2;
}
console.log(strict());
The first one doesn't use a declaration keyword, so f1 will become global (which defeats the purpose of the IIFE). But, that is legal syntax for an expression - the function can be invoked and the result (if any) can be assigned to f1. Note that this won't work with use strict in effect.
(f1 = function(){console.log('IIFE Block1')})()
// f1 is Global and can be accessed from anywhere
console.log(f1);
The second one fails because it's invalid IIFE syntax - it is a declaration and assignment statement, which is not an expression that can be evaluated.
(var f1 = function(){console.log('IIFE Block2')})()
In addition to all the great answers, you'll realize that most of this is syntactic allowance. You can apply the same methodology of the first one, which is operating on the window object, to any other defined object:
(f1 = function(){console.log('IIFE Block1')})()
console.log(f1);
// managed object
var local = {};
(local.f2 = function(){console.log('IIFE Block2')})()
console.log(local.f2);
// or any predefined variable
var f3;
(f3 = function(){console.log('IIFE Block3')})()
console.log(f3);
// just not in the parens
// (var f4 = function(){console.log('IIFE Block4')})()
// console.log(f4);
Related
Is there a way to get the Function object, while the function is executing?
I am assigning properties to my function, and want to access them. "this" doesn't help. Something like:
a.b=function(){...code...};
a.b.c=100;
I want to access a.b.c from the code in the function, without knowing its own name. "this" refers to a. How can get b?
I tried binding the function to his own object, but I couldn't.
Thank you.
I'm adding this example, I have to repeat after several different "theString" and "someSpecificValues":
Object.defineProperty(theObject, theString, {get: function(...){...}.bind(theObject, someSpecificValues), configurable: true});
You can use a named function expression for this:
var a = {};
a.b = function myFunc() {
console.log(myFunc.c);
};
a.b.c = 100;
a.b();
It allows code inside the function to access the function itself, but does not add the identifier to the enclosing scope.
Edit: Here is a more elaborate example of how the name myFunc only exists within the function:
var a = {};
a.b = function myFunc() {
console.log(myFunc.c);
};
a.b.c = 100;
a.d = function myFunc() {
console.log(myFunc.c);
};
a.d.c = 300;
a.b(); // logs 100
a.d(); // logs 300
console.log(typeof myFunc); // logs "undefined"
// create a myFunc variable
var myFunc = function() {
console.log("nooooooo!!!!");
};
a.b(); // STILL logs 100. the myFunc variable in this scope
// has no effect on the myFunc name that a.b uses
function callFunc(theFunc) {
theFunc();
}
callFunc(a.d); // STILL logs 300
// ===========================
function returnNamedFunction () {
return function myFunc() {
console.log(myFunc.c);
};
}
var iGotAFunction = returnNamedFunction();
iGotAFunction.c = 700;
iGotAFunction(); // logs 700
In the case when you cannot use a named function expression, e.g. when you are using .bind() on it, then an IIFE will suffice most of the time:
var myObj = {};
myObj.theFunc = (function () {
var f = function (arg1, arg2) {
console.log(this.theProp);
console.log(arg1);
console.log(arg2);
console.log(f.lista);
}.bind(myObj, "A!");
return f;
})();
myObj.theProp = "B!";
myObj.theFunc.lista = [1, 2, 3];
myObj.theFunc("C!");
There are two ways to get current function.
One is "almost deprecated" usage of arguments.callee. In function body it always refers to this function.
var a = {};
a.b = function () {
console.log(arguments.callee.c);
};
a.b.c = 100;
a.b();
arguments.callee is forbidden in strict mode. Reference.
The second one is using named function expression as JLRishe pointed.
arguments.callee pros and cons
Advantages:
it can be safely used with bound functions (arguments.callee refers to bound function)
it can be used with functions created using new Function
Disadvantages:
it can slow your program due to disabling certain optimisations
it's considered as almost deprecated
it can't be used in strict mode
Named function expression pros and cons
Advantages:
it's faster than arguments.callee
it's easier to understand how it works
Disadvantages:
it won't work as expected with bound functions (functionName will refer to original function, not bound one)
it can't be used in functions created with new Function
I've been wondering what is the difference between:
function getBasicRow() {}
getBasicRow : function() {}
I've seen the 2nd function used by vtiger CRM and hifive (http://www.htmlhifive.com/)
The second one assigns the function to a property on some object literal, so the scope of the function is determined by the property.
The first one creates a named function without assigning it to a variable. The function will be hoisted to the closest function scope.
An elobrative explanation that I found here and would like to share it.
The different ways in which a function can be defined in javascript are:
function A(){}; // function declaration
var B = function(){}; // function expression
var C = (function(){}); // function expression with grouping operators
var D = function foo(){}; // named function expression
var E = (function(){ // immediately-invoked function expression (IIFE) that returns a function
return function(){}
})();
var F = new Function(); // Function constructor
var G = new function(){}; // special case: object constructor
What exactly is hoisting?
The interesting thing about these is that they are “hoisted” to the top of their scope, which means this code:
A();
function A(){
console.log('foo');
};
Gets executed as this code:
function A(){
console.log('foo');
};
A();
Which practically means that, yes, you can call the functions before they’re written in your code. It won’t matter, because the entire function gets hoisted to the top of its containing scope.
Variable declaration hoisting
Variable declarations are hoisted to the top of their scope, somewhat similarly to function hoisting except the contents of the variable are not hoisted as well. This happens with all variables, and it means it’s now happening with our functions, now that we’re assigning them to variables.
This code:
var A = function(){};
var B = function(){};
var C = function(){};
Will be executed as this:
var A, B, C; // variable declarations are hoisted
A = function(){};
B = function(){};
C = function(){};
Therefore the order of setting and calling this type of function is important:
// this works
var B = function(){};
B();
// this doesn't work
B2(); // TypeError (B2 is undefined)
var B2 = function(){};
The second example gives us an error because only the variable B2’s declaration is hoisted, but not its definition, thus the “undefined” error.
Courtesy: DavidBCalhoun
I understand functions in 'js' have lexical scope (i.e. functions create their environment (scope) when they are defined not when they are executed.)
function f1() {
var a = 1;
f2();
}
function f2() {
return a;
}
f1(); // a is not defined
When I run just 'f()' it returns the inner function. Which I get, that's what 'return' does!
function f() {
var b = "barb";
return function() {
return b;
}
}
console.log(b); //ReferenceError: b is not defined
Why do you get 'ReferenceError: b is not defined?'
But doesn't the inner function above have access to it's space, f()'s space etc. Being that 'b' is being returned to the global space, wouldn't the console.log() work?
However when I assign 'f()' to a new variable and run it:
var x = f();
x();// "barb"
console.log(b); //ReferenceError: b is not defined
This returns 'b' which is "barb", but when you run console.log() again you'll get 'ReferenceError: 'b' is not defined'; Isn't 'b' in the global scope now since it has been returned? SO why didn't 'x()' also return the inner function just like 'f()' did?
You, my friend, are thoroughly confused. Your very first statement itself is wrong:
functions create their environment (scope) when they are defined not when they are executed
Actually it's the opposite. Defining a function doesn't create a scope. Calling a function creates a scope.
What's a scope?
To put it simply, a scope is the lifespan of a variable. You see, every variable is born, lives and dies. The beginning of a scope marks the time the variable is born and the end of the scope marks the time it dies.
In the beginning there's only one scope (called the program scope or the global scope). Variables created in this scope only die when the program ends. They are called global variables.
For example, consider this program:
const x = 10; // global variable x
{ // beginning of a scope
const x = 20; // local variable x
console.log(x); // 20
} // end of the scope
console.log(x); // 10
Here we created a global variable called x. Then we created a block scope. Inside this block scope we created a local variable x. Since local variables shadow global variables when we log x we get 20. Back in the global scope when we log x we get 10 (the local x is now dead).
Block Scopes and Function Scopes
Now there are two main types of scopes in programming - block scopes and function scopes.
The scope in the previous example was a block scope. It's just a block of code. Hence the name. Block scopes are immediately executed.
Function scopes on the other hand are templates of block scopes. As the name suggests a function scope belongs to a function. However, more precisely, it belongs to a function call. Function scopes do not exist until a function is called. For instance:
const x = 10;
function inc(x) {
console.log(x + 1);
}
inc(3); // 4
console.log(x); // 10
inc(7); // 8
As you can see every time you call a function a new scope is created. That's the reason you get the outputs 4, 10 and 8.
Originally, JavaScript only had function scopes. It didn't have block scopes. Hence if you wanted to create a block scope then you had to create a function and immediately execute it:
const x = 10; // global variable x
(function () { // beginning of a scope
const x = 20; // local variable x
console.log(x); // 20
}()); // end of the scope
console.log(x); // 10
This pattern is called an immediately invoked function expression (IIFE). Of course, nowadays we can create block scoped variables using const and let.
Lexical Scopes and Dynamic Scopes
Function scopes can again be of two types - lexical and dynamic. You see, in a function there are two types of variables:
Free variables
Bound variables
Variables declared inside a scope are bound to that scope. Variables not declared inside a scope are free. These free variables belong to some other scope, but which one?
Lexical Scope
In lexical scoping free variables must belong to a parent scope. For example:
function add(x) { // template of a new scope, x is bound in this scope
return function (y) { // template of a new scope, x is free, y is bound
return x + y; // x resolves to the parent scope
};
}
const add10 = add(10); // create a new scope for x and return a function
console.log(add10(20)); // create a new scope for y and return x + y
JavaScript, like most programming languages, has lexical scoping.
Dynamic Scope
In contrast to lexical scoping, in dynamic scoping free variables must belong to the calling scope (the scope of the calling function). For example (this is also not JS - it doesn't have dynamic scopes):
function add(y) { // template of a new scope, y is bound, x is free
return x + y; // x resolves to the calling scope
}
function add10(y) { // template of a new scope, bind y
var x = 10; // bind x
return add(y); // add x and y
}
print(add10(20)); // calling add10 creates a new scope (the calling scope)
// the x in add resolves to 10 because the x in add10 is 10
That's it. Simple right?
The Problem
The problem with your first program is that JavaScript doesn't have dynamic scoping. It only has lexical scoping. See the mistake?
function f1() {
var a = 1;
f2();
}
function f2() {
return a;
}
f1(); // a is not defined (obviously - f2 can't access the `a` inside f1)
Your second program is a very big mess:
function f() {
var b = "barb";
return function() {
return b;
}
}
console.log(b); //ReferenceError: b is not defined
Here are the mistakes:
You never called f. Hence the variable b is never created.
Even if you called f the variable b would be local to f.
This is what you need to do:
function f() {
const b = "barb";
return function() {
return b;
}
}
const x = f();
console.log(x());
When you call x it returns b. However that doesn't make b global. To make b global you need to do this:
function f() {
const b = "barb";
return function() {
return b;
}
}
const x = f();
const b = x();
console.log(b);
Hope this helped you understand about scopes and functions.
You get, "ReferenceError: b is not defined" because "b" is not defined where your console.log() call is. There's a "b" inside that function, but not outside. Your assertion that "b is being returned to the global space" is false.
When you invoke the function returned by your "f()" function, that will return a copy of the value referenced by that closure variable "b". In this case, "b" will always be that string, so the function returns that string. It does not result in the symbol "b" becoming a global variable.
But doesn't the inner function above have access to it's space, f()'s space etc.
Yes it has. It accesses the b variable and returns its value from the function.
Being that 'b' is being returned to the global space
No. Returning a value from a function is not "making a variable available in the caller scope". Calling the function (with f()) is an expression whose result is the value that the function returned (in your case, the unnamed function object). That value can then be assigned somewhere (to x), a property of it can be accessed or it can be discarded.
The variable b however stays private in the scope where it was declared. It is not [getting] defined in the scope where you call console.log, that's why you get an error.
What you want seems to be
var x = f();
var b = x(); // declare new variable b here, assign the returned value
console.log( b ); // logs "barb"
function f1() {
var a = 1;
f2();
}
function f2() {
return a;
}
f1(); // a is not defined
f2(); does not knows about the a,because you never passed 'a' to it,(That's Scope are
created when the functions are defined).Look function f2() would have been able to acess
a if it was defined inside f1();[Functions can access the variables in same scope in
which they are "DEFINED" and NOT "CALLED"]
function f() {
var b = "barb";
return function(){
return b;
}
}
console.log(b);
First of all You Need to Call f(); after executing f(); it would return another function
which needs to be executed. i.e
var a=f();
a();
it would result into "barb" ,In this case you are returning a function not the var b;
function f() {
var b = "barb";
return b;
};
console.log(f());
This would print barb on screen
I came across this type function in an example code, and it looks widely used. But I cannot figure out how to call this, or infact, what pattern it represents.
l = function (a1){
someVar = {
someFn: function(a2){
console.log(a1);
console.log(a2);
}
}
}
How would i go about executing someFn? Does this have something to do with closures?
UPDATE:
This is how the code is being used. As #joseph-the-dreamer guessed, it is being used as part of a module, where:
App.module("Module", function(a1) {
someVar = {
someFn: function(a2){
console.log(a1);
console.log(a2);
}
}
})
From it's current state, you need to call l first to set someVar to access someFn. Otherwise, you can't access someFn at all.
But without any variable declaration of someVar, calling l will create an implied global someVar. Implied globals isn't a good practice. You should declare someVar somewhere, even if you mean it to be a global.
var someVar;
l = function (a1){
someVar = {
someFn: function(a2){
console.log(a1);
console.log(a2);
}
}
}
l(1);
someVar.someFn(2);
//1
//2
You can also return someVar from calling l to access someVar. Note that this time, someVar is a local variable in l.
var l = function (a1){
var someVar = {
someFn: function(a2){
console.log(a1);
console.log(a2);
}
}
return someVar;
}
l(1).someFn(2);
As for pattern, I think what you have there is an incomplete form of the module pattern. Usually, module pattern wraps things in an IIFE, and returns an object as an interface to the module.
If someVar is not a variable in a scope outside of l(), then you cannot call someFn(), since someFn() is a private member function of someVar.
Otherwise, if you do have access to someVar, then you can call someFn() like this someVar.someFn(). Note that in this case, the console.log(a1) will behave strangely since a1 is has been assigned only since the last time l() was called.
In JavaScript there are 2 types of variables: global and local.
//local
var foo = "foo";
//global
bar = "bar";
From what I see in your sample, l is a global variable that is used to store an anonymous function. Inside this function there is a global variable named someVar that stores an object that has a local variable named someFn that stores an anonymous function.
To execute someFn, you must do the following:
l("Foo"); //This does not output anything
someVar.someFn("Bar"); //This will output "Foo" and then "Bar"
When you call l("Foo");, you are creating the global variable someVar. This in turn means you can use someVar anywhere even outside of the scope of the anonymous function stored in l. You are using closures for the argument a1.
A global variable can be used anywhere and I humbly suggest to limit its usage as it will pollute the global scope which means that it is quite error prone.
An approach that does not use global variables would be better. Little example here:
"use strict";
var l = function(a1) { //constructor
var _a1 = a1; //private variable
this.someFn = function(a2) { //public method
console.log(_a1);
console.log(a2);
};
};
var object1 = new l("Foo");
var object2 = new l("Foo");
object1.someFn(1); //outputs "Foo" and then 1
object2.someFn(2); //outputs "Foo" and then 2
I thought any variable defined in a function would be local but I can easily access variable 'e' outside of its function.
function change() {
var d = 6;
e = 7;
}
change();
alert(e); //> alerts 7
Because new variables will enter the global scope by default. var prevents this from happening by constraining a variable's existence to be within the current scope.
Because it was declared without var it becomes part of the global window object.
You've not explicitly declared it as such, so it has taken global scope.
Thats because e is global by default, using var make a scope varible.
You can read more about this in Javascript Garden Scope and Namespaces
I am guessing that you are going under this assumption that
JSLint expects that a var will be
declared only once, and that it will
be declared before it is used.
Problem with your code is you are using one var, but your second line has no var in front of it. That is pushing that varaible e into the global namespace.
Why is it happening? You used a semicolon instead of a comma in the variable declaration.
function change() {
var d = 6, //Change this to a comma
e = 7;
}
change();
alert(e); //will produce an error now
It is surprisingly easy to create global variables, here are some other gotchas I've seen.
// :-( antipattern: implied global variable
function sum(x, y) {
result = x + y; // result is global
return result;
}
// :-) better
function sum(x, y) {
var result = x + y; // result is local
return result;
}
// :-( antipattern: chain assignments as part of a var declaration
function foo() {
var a = b = 0; // b is global
}
// :-) better
function foo() {
var a, b;
a = b = 0; // both local
}