This question already has answers here:
Javascript function cannot be found
(5 answers)
Closed 8 years ago.
Recently I noticed a behavior difference between Firefox and other browsers for the following javascript code:
var condition = true;
A();
function A() {
var x=0;
for(var i=0; i<10; i++) {
if(condition) {
++x;
B();
}
function B() {
console.log("B function. x = "+x);
}
}
}
Chrome, Opera, IE output:
B function. x = 1
B function. x = 2
B function. x = 3
B function. x = 4
B function. x = 5
B function. x = 6
B function. x = 7
B function. x = 8
B function. x = 9
B function. x = 10
Firefox output:
ReferenceError: B is not defined
However, there are no complaints from Firefox and gives out the same result as other browsers, if I put the definition of function B before the call, like this:
for(var i=0; i<10; i++) {
function B() {
console.log("B function. x = "+x);
}
if(condition) {
++x;
B();
}
}
Based on this quote from Mozilla developer site:
Functions must be in scope when they are called, but the function declaration can be below the call
I understand the call, A() works. But I am not clear on why there is a difference in behavior between Firefox and others in calling B(), when the call is before definition.
While trying to narrow down the cause, I read about function hoisting here, which says Firefox doesnt do hoisting when inside an if block, but the definition was never inside the if statement in my case, so Im confused.
Firefox does not hoist function declarations outside of for blocks either. ECMA standard says it's okay. The documentation you linked to is not applicable only to if blocks, but for blocks as well.
Related
This question already has answers here:
Javascript function scoping and hoisting
(18 answers)
Closed 5 years ago.
I was running following JavaScript:
var foo = function() {
var a = 3,
b = 5;
var bar = function() {
var b = 7,
c = 11;
a += b + c;
console.debug(d);
};
bar();
console.debug(c);
var d = 10;
};
foo();
Clearly, d is not known to nested function bar and c is not known to external function foo. But in developer tools, when I load my web page I get two different logs one by one:
undefined
Uncaught ReferenceError: c is not defined
Why are the errors different for the two cases? In my opinion both should have thrown simply thrown reference error if the corresponding variable is not known to them or is out of scope.
The variable c died when function foo returned; c is local to bar because a var qualifier was used.
This question already has answers here:
Explanation of `let` and block scoping with for loops
(5 answers)
Closed 5 years ago.
function first(){
var items = document.getElementsByTagName("li");
for(var x = 0; x < items.length; x++){
items[x].onclick = function() {
console.log(x);
}
}
}
function second(){
var items = document.getElementsByTagName("li");
for(var x = 0; x < items.length; x++){
(function(val) {
items[val].onclick = function() {
console.log(val);
}
})(x);
}
}
function third(){
var items = document.getElementsByTagName("li");
for(let x = 0; x < items.length; x++){
items[x].onclick = function() {
console.log(x);
}
}
}
There are 4 elements in the list. Outputs of the 3 functions:
first: 4 4 4 4
second: 0 1 2 3
third: 0 1 2 3
I am not able to understand the output from the third function. In the second function, each call to the IIFE creates a new function object and hence, a new val variable. But in the third function, there is a single copy of the variable x, then how is the output: 0 1 2 3
Please correct me if I am wrong.
In the documentation for let from MDN they have an example covering this exact case in the Cleaner Code in inner functions section:
for (let i = 1; i <= 5; i++) {
let item = document.createElement('li');
item.appendChild(document.createTextNode('Item ' + i));
item.onclick = function(ev) {
console.log('Item ' + i + ' is clicked.');
};
list.appendChild(item);
}
The example above works as intended because the five instances of the (anonymous) inner function refer to five different instances of the variable i. Note that it does not work as intended if you replace let with var, since all of the inner functions would then return the same final value of i: 6. Also, we can keep the scope around the loop cleaner by moving the code that creates the new elements into the scope of each loop.
The same thing applies to your case, because you use let each anonymous function refers to a different instance of x. There is a different instance on each iteration of the loop. This happens because let has a block-level scope instead of the global function scope that var has.
From the docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
let allows you to declare variables that are limited in scope to the
block, statement, or expression on which it is used. This is unlike
the var keyword, which defines a variable globally, or locally to an
entire function regardless of block scope.
When it is var it gets hoisted like all variables.
When it is let the scope is the block it is defined in.
This is one of the trickiest examples of let keyword.
The fact that Let binds variables to the block(& in this case for-loop) means that it binds the variable to every iteration of the loop. So, when loop is finished, you have 4 items (items from item[0] to item[3]) listening to click event.
In fact the for-loop in the third function produces the following:
items[0].onclick = function() {
console.log(0);
}
items[1].onclick = function() {
console.log(1);
}
items[2].onclick = function() {
console.log(2);
}
items[3].onclick = function() {
console.log(3);
}
Make sure to read more about Let here in MDN Some other exciting cases could be found there.
I'm beginner with Javascript and my teacher gave me this code :
var z = (x=>(y=>2*y)(x)+3)(5);
(Sorry for my English, I'm a French guy with a bad level of English ^^)
I have to re-write this code with simple functions but I'm not sure of myself.
For me, I can re-write this code like :
var x = 5;
var y = 2 * x;
var z = y + 3;
But, it's not re-write with simples functions.
My question is : can you help me to understand how arrow function works in this case and give me an idea how to re-write this code with simple functions.
Arrow functions that have a => b form implicitly return b when called. You can imagine them like:
function (a) { return b }
Additionally, your code sample is wrapped in () and immediately invoked, pattern known as the Immediately Invoked Function Expression (IIFE):
(a => b)(3)
which is the same as
(function (a) { return b })(3)
Where both functions get defined and invoked immediately, hence the name.
Now all you have to do is use these two ideas, implicit returns and IIFEs for arrow functions, to re-write your example as plain functions with explicit returns and regular IIFEs.
In other words:
Add return statements where they are assumed to exist (implicit in arrow functions)
Add function() around each arrow function's arguments.
Here's what is happening in your code sample in plain English:
Pass 5 into an IIFE which takes x
Pass that x down to another IIFE which takes y
Return 2 * y from the second IIFE
Add 3 to what was return from second IIFE
Return result from the first IIFE
Or as a math formula:
z = x = (2 * y) + 3
We have:
var z = (x=>(y=>2*y)(x)+3)(5);
The arrow function definition says that x=>(....) means (function(x){ return ...})
So
var z = (function(x) {
return (y=>2*y)(x)+3;
})(5);
We have now another arrow function y=>2*y, that means (function(y) { return 2*y}).
So
var z = (function(x) {
return (function(y) {
return 2*y;
})(x) + 3;
})(5);
And that's all.
Remember that (function(){})() it's an anonymous function declaration executed immediately. So at the end, the var z is a simple number.
I was answering a question on quora and encountered something like following:
// if(true)
{
var qq = 1;
}
Immediately I fired up chrome and tried the following
{
var qq = 1;
}
To my surprise no syntax errors. I thought this might be a way to set up a closure without a function, but alas nothing like that is true.
Why is this valid JavaScript? Does this serve some purpose? Are there any issues due to this?
The blocks are used just for statements like if(){}, function(){}, switch(){}, for(..){}, etc.
In this example:
var number = 0;
if(true)
number = 1
else
number = 2
number = 3 //This line is evaluated because no longer is in the `else` condition
console.log(number); //3
Using blocks this will not happen:
var number = 0;
if(true)
{
number = 1
}
else
{
number = 2
number = 3
}
console.log(number); //1
Using blocks without using any statement are unnecessary, eg:
var foo = 2;
foo = 3;
console.log(foo) //3
It is the same as doing:
var foo = 2;
{
foo = 3;
}
console.log(foo) //3
Except if you are developing in an environment of ES6. Using let declarations in blocks are very important. And these will be evaluated only within the block.
let foo = 2;
{
let foo = 3;
}
console.log(foo) //2
It is a block.
Syntactically, a block is just a bunch of statements that are grouped together.
Block : { StatementList }
StatementList
: StatementListItem
| StatementList StatementListItem
StatementListItem
: Statement
| Declaration
But here's the tricky part: blocks are statements, too.
Statement : BlockStatement
BlockStatement : Block
And there you have it, now you can define compound statements such as if or while in terms of an abstract Statement, without having to worry about whether it is a single statement or a block.
IfStatement
: if ( Expression ) Statement else Statement
| if ( Expression ) Statement
IterationStatement
: while ( Expression ) Statement
| for ( LeftHandSideExpression in Expression ) Statement
| for ( LeftHandSideExpression of AssignmentExpression ) Statement
Isn't it beautiful?
As a side effect of this language design, blocks can contain other blocks inside — it isn't worth prohibiting this quirk explicitly in the language specification, although semantically in EcmaScript 5.1 inner blocks were indeed superfluous and very rarely used.
{
var x = 1;
{
var x = 2; // The same variable as in the outer block.
console.log(x); //=> 2
}
console.log(x); //=> 2
}
In the latest EcmaScript 6 (2015) standard, however, such blocks do have semantic value, as shown in the next example:
{
let x = 1;
{
let x = 2; // New variable, visible in this block only.
console.log(x); //=> 2
}
console.log(x); //=> 1
}
let and const are block-scoped variable declarations introduced by ES6.
This question already has answers here:
How do I define global variables in CoffeeScript?
(9 answers)
Closed 10 years ago.
With javascript:
function myFunc() {
var x = 5;
};
console.log(x);
I get //undefined and with:
function myFunc() {
x = 5;
};
console.log(x);
I get 5
With coffeescript this variable var x = 5; is x = 5.
For example this is possible?:
myFunc ->
window.x = 5;
console.log window.x
Instead of:
myFunc ->
x = 5;
console.log x
My question is How I can differentiate a global variable of a local variable with CoffeeScript?
for global scope you should use functions like this:
myFunc = =>
#x = 5;
myFunc()
console.log x
example of generated code:
http://jsfiddle.net/Upward/wZ7w4/