Firefox: function hoisting error - javascript

I used to assume that functions always get hoisted to the top of any block of JavaScript code.
For example, this works:
document.addEventListener('something', dummy);
function dummy(){
console.log('dummy');
}
but this doesn't work and throws ReferenceError in Firefox, but works in Chrome:
if(document){
document.addEventListener('something', dummy1);
function dummy1(){
console.log('dummy');
}
}
Fiddle code
Initially, I assumed that Chrome would also throw an error before I tested, but somehow it works correctly. Can someone explain why it doesn't work in Firefox?

It appears this has been an issue for quite a while - here's a reference from 2011: http://statichtml.com/2011/spidermonkey-function-hoisting.html
Apparently Firefox will happily hoist function declarations OUTSIDE of a block, but doesn't do so INSIDE a block. The author of the linked article argues this is (while unexpected) compliant with the ECMA-262 spec, which only allows statements inside of a block...as a function declaration is not a statement. However, I'll note that Firefox happily allows function declarations inside of a block - it merely refuses to hoist them.

Related

Scoping of function declarations within `with` statements

Preface: Use of with is discouraged in JavaScript for good reason. It can lead to confusing code, and forward compatibility problems (when new properties are added to built-in objects, for example). This question isn't about whether or not with should be used - it's about the spec-defined behavior of with.
Should the following code work?
let foo = {};
with(foo) {
function bar() {
console.log("hello");
}
}
bar();
It works in Chrome 80, but not in Firefox 72: TypeError: bar is not a function.
Edit: Turns out this error only occurs when pasting into the Firefox console (https://i.imgur.com/WTG3iiX.png), not when running the code within a HTML document.
But notice it's a TypeError, and not a ReferenceError (i.e. bar is not defined). To confirm this we can add console.log("bar" in window) before bar();, and notice that outputs true in Firefox, whereas if you write that before the code it outputs false. So in Firefox the above code has the effect of setting window.bar to undefined.
This works fine in both Firefox and Chrome:
if(true) {
function bar() {
console.log("hello");
}
}
bar();
Just as I'd have expected, since a function foo() {...} declaration is function scoped. So unless there's something weird about with block scopes, it seems like this is a Firefox bug?
I haven't been able to reproduce the problem with Firefox 73, so Firefox's behaviour may have changed.
That said, see MDN on the subject of blocks:
In strict mode, starting with ES2015, functions inside blocks are scoped to that block. Prior to ES2015, block-level functions were forbidden in strict mode.
IIRC, the interaction between hoisting rules and blocks was undefined which resulted in different behaviour in different JS engines. This isn't so much a Firefox bug as a bug in the definition of the language itself.
Avoid function declarations in blocks.

Value of variable is always undefined [duplicate]

alert(myVar1);
return false;
var myVar1;
Above code throws error in IE, FF and Opera stating that return statement has to come in the function. But it works (shows undefined) in Safari and Chrome.
The above code has been written in global scope. Outside all the functions.
Any reason?
In JavaScript variables are moved to the top of script and then run. So when you run it will do
var myVar1;
alert(myVar1);
return false;
This is because JavaScript doesn't really have a true sense of lexical scoping. This is why it's considered best practice to have all your variables declared at the top of the area they will be used to prevent hoisting causing a problem. JSLint will moan about this.
This is a good article that explains it: http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting
The return is invalid. If you want to do a true hoisting example (taken from the link above) do
var foo = 1;
function bar() {
if (!foo) {
var foo = 10;
}
alert(foo);
}
bar();
This will alert 10
Below is my understanding and I have read it somewhere but can't find all the sources that I read so am open to correction.
This Alerts thanks to the differences in the JavaScript JIT. TraceMonkey(http://ejohn.org/blog/tracemonkey/) I believe will take the JavaScript and do a quick static analysis and then do JIT and then try to run it. If that fails then obviously nothing works.
V8 doesn't do the static analysis and moves to the JIT then runs so something. It's more akin to Python. If you run the script in the Developer console (ctrl+shift+j in Windows) in Chrome it will throw an error but also run to give you the alert.
Sometimes hoisting is explained in a way which may give wrong impression, i.e. the variables and functions are hoisted by JavaScript engine as if they were physically moved on top, which is not actually right, as demonstrated by the code below:
console.log(a);
var a = 'Hello World!';
What we see on console is undefined, not 'Hello World', so we got the behavior of the following code
var a;
console.log(a);
a = 'Hello World!';
not the behavior of
var a = 'Hello World!';
console.log(a);
which you may get the impression from the variables and functions declaration being moved to top statement.
But JavaScript is not actually moving your code anywhere. You need to understand execution context in JavaScript. It has two phases creation phase and execution phase. In creation phase memory space is created for these variables and functions, and people seem to confuse this step with hoisting. JavaScript is actually not moving your code anywhere, what happens is JavaScript has created memory space for all your code i.e. variables and functions, functions can be placed fully in memory but in case of variables the assignments are processed in execution phase of the execution context. So when you do var a = 'Hello World!', JavaScript engine knows the value of a when it starts executing it in execution phase of execution context, so it puts a placeholder undefined, and all variables are initially set to undefined in JavaScript. So it is not good to rely on hoisting and see undefined. So it is always good to declare variables and functions on top of your code.
Section 12.9 (page 75) of ECMA-262 edition 3 states:
An ECMAScript program is considered syntactically incorrect if it contains a return statement that is not within a FunctionBody.
That is, a return outside of a function is a syntax error. If a syntax error occurs, no code is run. Think about your example as if you had written:
alert(myVar1);
return false;
syntax error))))))))))))))))));
In addition, section 16 (page 157) states:
An implementation may treat any instance of the following kinds of runtime errors as a syntax error and therefore
report it early:
Improper uses of return, break, and continue.
Firefox's engine et. al. (i.e. those JavaScript implementations which allow return in the global scope) may be conforming, assuming the following clause (in the same section) allows for implementation definition of return in the global scope:
An implementation shall report all errors as specified, except for the following:
An implementation may provide additional types, values, objects, properties, and functions beyond those described in this specification. This may cause constructs (such as looking up a variable in the global scope) to have implementation-defined behaviour instead of throwing an error (such as ReferenceError).
This code makes little sense:
The var myVar1 will never be ran.
The return false; will not return a thing since you're not in a function
Opera, IE and FF are right to throw an error because this code is really not valid since you're not able to return unless you are in a function.
If it works in Safari and Chrome it must be because the javascript engine they use is ready to handle buggy code. My guess would be that they see the "return" and drop or replace it with some kind of break.
More information about functions: http://www.w3schools.com/js/js_functions.asp
It is JavaScript Hoisting thing, Simply in other words, we are trying print the value of the variable , which is not holding any value
Javascript will render the above code as:-
var myVar1
alert (myVar1)
return false
To clarify more i refered the link javascript hoisting: http://www.ufthelp.com/2014/11/JavaScript-Hoisting.html

Firefox not prereading functions [duplicate]

I used to assume that functions always get hoisted to the top of any block of JavaScript code.
For example, this works:
document.addEventListener('something', dummy);
function dummy(){
console.log('dummy');
}
but this doesn't work and throws ReferenceError in Firefox, but works in Chrome:
if(document){
document.addEventListener('something', dummy1);
function dummy1(){
console.log('dummy');
}
}
Fiddle code
Initially, I assumed that Chrome would also throw an error before I tested, but somehow it works correctly. Can someone explain why it doesn't work in Firefox?
It appears this has been an issue for quite a while - here's a reference from 2011: http://statichtml.com/2011/spidermonkey-function-hoisting.html
Apparently Firefox will happily hoist function declarations OUTSIDE of a block, but doesn't do so INSIDE a block. The author of the linked article argues this is (while unexpected) compliant with the ECMA-262 spec, which only allows statements inside of a block...as a function declaration is not a statement. However, I'll note that Firefox happily allows function declarations inside of a block - it merely refuses to hoist them.

Why are function declarations handled differently in different browsers?

Although I couldn't find a reference to this easily in google, I'm familiar with the fact that, in javascript, global function declarations get interpreted before any code is executed. In other words, this works fine:
f();
function f() {}
However, I've noticed that chrome and firefox have different interpretations of what a global function declaration is. In particular, chrome is happy reading a function declaration that is inside an if block in the first pass, but firefox is not.
try {document.write(f);} // works in chrome
catch(e) {document.write(e.message);} // throws an error in firefox
try {document.write(g);} // works in chrome and firefox
catch(e) {document.write(e.message);}
if(true) function f() {}
function g() {}
You can try this example yourself with this fiddle. I'm using Chrome 16.0.912.75 and Firefox 9.0.1.
What is the ECMA standard for this behavior? Is there a term for this process of "lifting" function declarations above other code? Is what code gets "lifted" open to interpretation (are both browsers right)? Or is it a bug in one of them?
This answer is outdated since the release of ES6 in 2015. See What are the precise semantics of block-level functions in ES6? for how it works since then.
Function declarations are not valid in blocks. You have undefined behaviour which is undefined.
Function declarations at a top level (either global or top level within a function) are hoisted.
Function declarations inside blocks are a syntax error in strict mode
(function () {
"use strict";
if (true) {
function g() { }
}
})();
SyntaxError: In strict mode code, functions can only be declared at top level or immediately within another function.
The ECMA standard for this behavior is to throw a SyntaxError when parsing the script. Unfortunately doing that is not compatible with the web as Raynos says.
See Which JS function-declaration syntax is correct according to the standard? for some extended discussion on the issue.

Why variable hoisting after return works on some browsers, and some not?

alert(myVar1);
return false;
var myVar1;
Above code throws error in IE, FF and Opera stating that return statement has to come in the function. But it works (shows undefined) in Safari and Chrome.
The above code has been written in global scope. Outside all the functions.
Any reason?
In JavaScript variables are moved to the top of script and then run. So when you run it will do
var myVar1;
alert(myVar1);
return false;
This is because JavaScript doesn't really have a true sense of lexical scoping. This is why it's considered best practice to have all your variables declared at the top of the area they will be used to prevent hoisting causing a problem. JSLint will moan about this.
This is a good article that explains it: http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting
The return is invalid. If you want to do a true hoisting example (taken from the link above) do
var foo = 1;
function bar() {
if (!foo) {
var foo = 10;
}
alert(foo);
}
bar();
This will alert 10
Below is my understanding and I have read it somewhere but can't find all the sources that I read so am open to correction.
This Alerts thanks to the differences in the JavaScript JIT. TraceMonkey(http://ejohn.org/blog/tracemonkey/) I believe will take the JavaScript and do a quick static analysis and then do JIT and then try to run it. If that fails then obviously nothing works.
V8 doesn't do the static analysis and moves to the JIT then runs so something. It's more akin to Python. If you run the script in the Developer console (ctrl+shift+j in Windows) in Chrome it will throw an error but also run to give you the alert.
Sometimes hoisting is explained in a way which may give wrong impression, i.e. the variables and functions are hoisted by JavaScript engine as if they were physically moved on top, which is not actually right, as demonstrated by the code below:
console.log(a);
var a = 'Hello World!';
What we see on console is undefined, not 'Hello World', so we got the behavior of the following code
var a;
console.log(a);
a = 'Hello World!';
not the behavior of
var a = 'Hello World!';
console.log(a);
which you may get the impression from the variables and functions declaration being moved to top statement.
But JavaScript is not actually moving your code anywhere. You need to understand execution context in JavaScript. It has two phases creation phase and execution phase. In creation phase memory space is created for these variables and functions, and people seem to confuse this step with hoisting. JavaScript is actually not moving your code anywhere, what happens is JavaScript has created memory space for all your code i.e. variables and functions, functions can be placed fully in memory but in case of variables the assignments are processed in execution phase of the execution context. So when you do var a = 'Hello World!', JavaScript engine knows the value of a when it starts executing it in execution phase of execution context, so it puts a placeholder undefined, and all variables are initially set to undefined in JavaScript. So it is not good to rely on hoisting and see undefined. So it is always good to declare variables and functions on top of your code.
Section 12.9 (page 75) of ECMA-262 edition 3 states:
An ECMAScript program is considered syntactically incorrect if it contains a return statement that is not within a FunctionBody.
That is, a return outside of a function is a syntax error. If a syntax error occurs, no code is run. Think about your example as if you had written:
alert(myVar1);
return false;
syntax error))))))))))))))))));
In addition, section 16 (page 157) states:
An implementation may treat any instance of the following kinds of runtime errors as a syntax error and therefore
report it early:
Improper uses of return, break, and continue.
Firefox's engine et. al. (i.e. those JavaScript implementations which allow return in the global scope) may be conforming, assuming the following clause (in the same section) allows for implementation definition of return in the global scope:
An implementation shall report all errors as specified, except for the following:
An implementation may provide additional types, values, objects, properties, and functions beyond those described in this specification. This may cause constructs (such as looking up a variable in the global scope) to have implementation-defined behaviour instead of throwing an error (such as ReferenceError).
This code makes little sense:
The var myVar1 will never be ran.
The return false; will not return a thing since you're not in a function
Opera, IE and FF are right to throw an error because this code is really not valid since you're not able to return unless you are in a function.
If it works in Safari and Chrome it must be because the javascript engine they use is ready to handle buggy code. My guess would be that they see the "return" and drop or replace it with some kind of break.
More information about functions: http://www.w3schools.com/js/js_functions.asp
It is JavaScript Hoisting thing, Simply in other words, we are trying print the value of the variable , which is not holding any value
Javascript will render the above code as:-
var myVar1
alert (myVar1)
return false
To clarify more i refered the link javascript hoisting: http://www.ufthelp.com/2014/11/JavaScript-Hoisting.html

Categories

Resources