Why was block scope not originally implemented in JavaScript? - javascript

I have read, and discovered through my own experience, that JavaScript doesn't have a block scope. Assuming that the language was designed this way for a reason, can you explain to me what is that reason?
I've looked around on Google and here, but the posts I have found just reiterate that JS has a function scope and not block scope, without explaining why. I'm curious to know why this is actually the case.

Converting my comment to answer
Choice of the creator: I tweeted Brendan and got the following answer:
#mplungjan 10 days did not leave time for block scope. Also many "scripting languages" of that mid-90s era had few scopes & grew more later.
That said, here are some relevant points:
Block statement
Important: JavaScript prior to ECMAScript2015 (6th edition) does not have block scope. Variables introduced within a block are scoped to the containing function or script, and the effects of setting them persist beyond the block itself. In other words, block statements do not introduce a scope. Although "standalone" blocks are valid syntax, you do not want to use standalone blocks in JavaScript, because they don't do what you think they do, if you think they do anything like such blocks in C or Java.
a workaround
we can artificially introduce scopes by creating new functions and immediately invoking them
ECMAScript 2015 (ES6)
let and const declared variables are hoisted but they are not initialized to undefined in the same way var is. Hence, referencing a let or const declared variable before its value is assigned raises a ReferenceError.
Redeclaration of the same variable in the same block scope raises a SyntaxError.

New answer as of 2015. ES6 does have block scope for variable definitions with the let and const keywords.

Block scope was not implemented for the following reasons:
It's makes the language easier to implement. JavaScript was initially designed as a language for writing interactive web applications. Hence it needed to be small and easy to implement.
Block scopes introduce a performance hit to dynamic languages like JavaScript. This is because when you try to access some variable which is not in the current scope JavaScript first checks the current scope, then the parent scope and so on until it either finds the variable or reaches the end. Hence the introduction of block scopes would make variable access in loops and nested loops very slow.
The lack of block scopes makes it easier to write programs. For example say you want to create a variable only if a certain condition is true. All you need to do in JavaScript is declare and define the variable within an if statement. In languages like C you would have to declare the variable outside the if statement and define it within the if statement.
The lack of block scopes allow declarations to be hoisted. This is especially useful in the case of function declarations. For example see this fiddle: http://jsfiddle.net/L6SgM/ (note however that this example doesn't work in Firefox).
Since JavaScript supports first-class function expressions we don't need block scopes. They can be simulated using immediately invoked function expressions.

There are many reasons, but some that come to mind are to aid in parsing/debugging code that uses object literals (which can sometimes look like a block), and to simplify the garbage collection of local variables.
I hope that the promised support (discussed here, for example, http://esdiscuss.org/notes/2012-07-25) turns out to be real because it would be very convenient to use variables like i that were local to only a single loop.

Related

Does automatically hoisting slow down the performance of JavaScript?

Lately, I was studying Scope in Javascript. I want to know whether automatically hoisting is done at compile time or at the time of executing the code(run time). If it does at run time then I have another question does auto-hoisting will slow down the performance of the Javascript program.
something = a();
function a(){
console.log("hoisting");
return 10;
}
var something;
Should we use manual hoisting or it would be better to use automatically hoisting?
To put my comments as an answer:
People have a different understanding of what hoisting supposed to mean. Fact is that, according to the spec, every time a function is called a new execution context is created, which holds a new environment. Then the function body is processed to find all variable declarations (var, let, const (and function declarations)) and bindings for those names are created in the new environment. var declarations are initialized with undefined. Then the body is actually evaluated.
Considering this, from the perspective of the engine it doesn't really matter where you place the var declaration, the whole body has to be processed anyway.
Having said that, I would be surprised if actual implementations didn't cache that information. After all, the variable declarations in a function don't change between function calls.
As I know, There are no performance issues. The initializations are getting done in compile time. So doesn't matter you initialize on top or bottom, The JS engine will create the references in compile time.
BUT
If you forgot to initialize at the bottom, It will be initialized as undefined by default. Because of hoisting it’s considered a practice to declare functions or variables at the top of their respective scopes.
JavaScript: What is Hoisting? (Recommended)
It is not done at run time.
It's in the compile process.
So it doesn't slow down the performance.
Just before the code is executed the compiler scans for all variable and function declarations and allocates them in the memory.

Is there any benefit from hoisting?

I would like to see which are the benefits of hoisting, if there's some... I looked for an answer but they only explain what is it, I would like to know is there's an actual benefit that I can use to write better code.
It seems that with the use of const and let, javascript is actually enforcing to avoid hoisting, not to mention that some linters actually enforce to declare functions and variables at the top from where they're called.
The main benefit of hoisting is that functions don't have to be declared in a specific order in order to work properly. The interpreter makes a pass over a function of code and finds all the function declarations within that function and makes them available to code anywhere in the scope (hoisting them) whether the code referring to the functions is before or after where the function declarations are located. It also allows A to call B and B to call A without running into declaration ordering issues.
Variable hoisting is rarely used anymore now that we have const and let which are block scoped and cannot be used before declaration. So hoisting is mainly useful for function declarations now.
In JavaScript, Hoisting is the default behavior of moving all the declarations at the top of the scope before code execution. Basically, it gives us an advantage that no matter where functions and variables are declared, they are moved to the top of their scope regardless of whether their scope is global or local.
It allows us to call functions before even writing them in our code.
Note: JavaScript only hoists declarations, not the initializations.

What is the main advantage of hoisting in Javascript?

A couple of days ago, I had an interview, and one of the questions was 'what is hoisting?' then I explained the hoisting concept thoroughly, then the interviewer asked me, 'what is the main advantage of hoisting?' I couldn't answer.
Really what is the main advantage of hoisting in javascript?
Convenience?
No really. It is convenient. Both to the reader of code as the coder themselves. Not so much for variable hoisting, but for function hoisting. This way you can put the helper functions to the bottom of your code and the more abstract ones which show your business logic at the top.
I like this answer on quora on the same topic https://www.quora.com/Why-does-JavaScript-hoist-variables
In other words, what happened was that JavaScript implemented hoisting of function declarations so that programmers would not be forced to place the inner-most functions at the top of the script block, and the outer-most (top-level) functions at the bottom. This order, which is forced in ML languages (such as LISP) is painful because programmers prefer reading code top-to-bottom, rather than bottom-to-top. Languages like C/C++ get around this issue by using header files, and standalone declarations, which JavaScript doesn’t have. Also, hoisting was required for implementing mutual recursion.
A name (variable name, function name) is scoped to its block. With var that's the function body, with let/const that's the closest enclosing {} block. Due to the nested scopes possible in Javascript, it must be clear which block a variable belongs to. If you mention var foo/let foo anywhere within a specific block, that block is reserved as the scope for this variable.
function () {
/**** scope of foo *****/
/*/
/*/ var foo;
/*/
/*/ function () {
/*/ /** scope of bar **/
/*/ /*/
/*/ /*/ var bar;
/*/ /*/
/*/ /******************/
/*/ }
/**********************/
}
It would be very confusing if the variable scope would only start at the exact line at which var ... is declared; then half the function would have one variable scope and half another. Hence, if var/let exists anywhere within a block, that name is hoisted to encompass the entire block.
Well, everything has its advantages and its disadvantages, but in this case, the disadvantages seem to outweigh the advantages.
In my opinion, hoisting makes the code harder to reason about. But that's just my opinion. When I write code, I want my bindings declared at the point in code where I declare them. That way, I get informed if I mistakenly use them before I declare them, for example. And I certainly do not want to accidentally declare them twice, which would be perfectly valid and perfectly confusing.
I would like the compiler/interpreter to help me when I do something stupid. Hoisting allows me to do too much convenient and/or stupid things, potentially resulting in hours of complex debugging sessions. So since ES6, I primarily use let and const instead of var. No hoisting for me if I can help it. ;)
So my answer to the question "What is the (main) advantage of hoisting?" would be: "I really don't care."
Edit:
Well, perhaps I am a little too harsh here. Function hoisting might actually be useful and convenient and improve readability of code. But within functions, I would avoid variable hoisting as much as possible.
Hosting is useful to create a chain of function calls. Like the ones RxJS offers
https://youtube.com/shorts/JTPozUVicGo?feature=share
Hoisting can be useful in some of the cases. For example we are creating a big project. It has alot of helper methods which are separated by putting then in another script. Now if they are declared using function declaration we don't have to worry about the order of scripts. Otherwise we could have issues.
Another use is that when we use recursion. Consider a function which prints numbers using recursion.
(function print(n){
if(n === 0) return;
console.log(n)
print(n-1)
})(4);
Now if there wouldn't be any hoisting the code may have thrown error that print is not defined

Is there a purpose to hoisting variables?

I've been learning a lot of Javascript lately and I've been trying to understand the value (if there is any) of hoisting variables.
I understand (now) that JS is a two pass system, it compiles and then executes. Also, I understand that the var keyword 'exists' in the lexical scope it was declared, hence why it's 'undefined' if it's called before it's assigned a value by the engine.
The question is, why does that even matter? What use is there to hoisting variables that you can't do without hoisting? I feel like it just creates less-readable code with no gain ...
is there an example(s) of where hoisting variables is useful?
"Hoisting" is necessary for mutually recursive functions (and everything else that uses variable references in a circular manner):
function even(n) { return n == 0 || !odd(n-1); }
function odd(n) { return !even(n-1); }
Without "hoisting", the odd function would not be in scope for the even function. Languages that don't support it require forward declarations instead, which don't fit into JavaScripts language design.
Situations that require them might arise more often that you'd think:
const a = {
start(button) {
…
button.onclick = e => {
…
b.start(button);
};
}
};
const b = {
start(button) {
…
button.onclick = e => {
…
a.start(button);
};
}
};
Not really. The only thing I can think of where it would be helpful is if you are writing code in a hurry and you happen to declare it later on. So it doesn't really matter, it's a weird addition to JS that a lot of people don't really even know about because utilizing it feels backwards and inefficient.
There is no such thing as hoisting. Hoisting is merely a side effect of the compile phase that occurs and the fact that Javascript is lexically scoped. When the compiler comes to the compile phase it puts all variable and function declarations in memory as it figures out the lexical scopes that exists in the program. But there is no hoisting function or keyword or module. In fact it wasn't even reference in the Ecmascript spec before the es2015 release.
At the end of the day, hoisting is one of those million dollar words we all use, often because its easier to use rather than explain and discuss the compilation process that javascript goes through.
My suggestion would be to either read through the Ecmascript specs, work through a javascript engine source like v8, or read up on Kyle Simpson's work. He wrote a great series called You Don't Know JS.
Hope this helps!
Hoisting is a term you will not find used in any normative specification prose prior to ECMAScript® 2015 Language Specification. Hoisting was thought up as a general way of thinking about how execution contexts (specifically the creation and execution phases) work in JavaScript. However, the concept can be a little confusing at first.
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. <- From the Mozilla docs
https://developer.mozilla.org/en-US/docs/Glossary/Hoisting

Why hoist variables when there is TDZ

The ES6 standard comes up with Temporal Dead Zones, making a variable reference not possible in any way until the lexical binding is evaluated. So what does variable creation at the time of lexical environment initialisation mean to
The programmer ?
The Compiler ?
The declaration of a variable using var declaration might mean something to the programmer previously, but now with TDZ in place does javascript start behaving like java for this purpose? Is there any reason other than the way javascript interpreter works that we have hoisting (as a result TDZ) in the first place?
What happens when a lexical binding is encountered later in the code due to order of execution even when the code appears before it lexically?
let abc = f();
let b;
f(){ return b;}
When does traditionally programming languages like java create variables? When the variable declaration is encountered? or when the lexical scope is initialised?
I have a feeling that the creation of TDZ had to do with it being a very menial step from var, whereas if they were to go with the seemingly more logical approach of not even having the identifier exist, the engine would have had to undergo even more intensive changes. As for the second part of your question in reference to when other languages "create" variables, there are many other important factors to consider that you seem to have left out, such as is the language interpreted vs compiled, as well as there are multiple different steps to "creating" a variable. It acts differently in many different cases, and there is no single answer. In fact, that is one of the big reasons why there are many different languages.
As for your coding question, it would depend on when you're calling your f function, since function declarations are hoisted in javascript. If you are calling it before b is declared, then you are in a TDZ and b cannot be referenced. It will behave very similarly as if you were simply putting the return b wherever this function is called.
Honestly, it seems as if there is some underlying misunderstanding of javascript, and computer languages in general. Javascript is not "behaving" more like java, in fact the new let keyword has very nuanced behavior, such as being able to be block scoped, compared to type/variable declarations in java. I would suggest not trying to think of the changes in ES6 in terms of other languages; javascript is not like a lot of other languages, it will be very difficult to understand the concepts and how you should be programming with javascript if you do.
EDIT:
As for why there is variable and function declaration hoisting, that is easily googlable.
So what does variable creation at the time of lexical environment
initialisation mean to the programmer?
Not much. A programmer only intends to use declared and initialised variables.
That the variable is available in the whole scope (from the beginning) only means that mistakes will be caught easier, as the usage of the variable prior to initialisation fails (with an exception) instead of silently being resolved to an outer-scope (global?) variable. It also means that the identifier, regardless where in the scope it is used, always refers to the local variable - which is just what we'd expect from a scope.
So what does variable creation at the time of lexical environment
initialisation mean to the Compiler?
That a lexical environment doesn't change its structure during execution. Static resolution of identifiers in a known scope makes compiling possible, and execution faster.
Just as a counterexample, consider this thing:
var x = "global";
var code = "var x = 'local';";
(function() {
"use sloppy";
function test() {
console.log(x); // what do you think does `x` refer to?
} // It's hard to understand as a developer,
// now imagine being a compiler that tries to optimise `test`.
test();
eval(code);
test();
}());
What happens when a lexical binding is encountered later in the code
due to order of execution even when the code appears before it lexically?
b is used by the call to f() before it's initialised. Accessing it throws a TDZ exception.
You can try it online.

Categories