MDN documentation states:
let bindings are created at the top of the (block) scope containing
the declaration, commonly referred to as "hoisting". Unlike variables
declared with var, which will start with the value undefined, let
variables are not initialized until their definition is evaluated.
Accessing the variable before the initialization results in a
ReferenceError. The variable is in a "temporal dead zone" from the
start of the block until the initialization is processed.
Is the "let binding" referrred to (the hoisting of let and const) just the keyword let, or is it just the creation of storage space (which doesn't have to do with the keyword)?
Previously I thought the variable keyword and variable name together comprised a declaration, but in a question I asked recently, the answerer said they are actually an initialization.
I'm sorry for using two different terms when writing that MDN paragraph. For all purposes in that article, "variable" and "binding" should be understood as the same thing. But let's go into details.
A variable declaration creates the variable (as an abstract entity). It tells the compiler that it should introduce a new variable, and also can tell it about a name, a type to be held, an initial value, a scope etc. (depending on the language). In JS, there are different kinds of declarations that do different things, for example
var has a name, an optional initialiser and scoping rules specific to var
function has a (sometimes optional) name, the value is always given and known to be a function
const has a name, a required initialiser, should be immutable, and has lexical scoping
…
A binding is the association of a variable name with the variable entity, for example "x refers to the variable declared with class x". Such bindings depend on the scope, i.e. in every different scope there are different bindings and so the identifier x might refer to different things in different scopes.
Given the scoping rules of JavaScript, a variable declaration also causes bindings for itself to be created in the respective scopes.
So the binding is what makes the name available to be used. That's what I referred to as "the let binding is created at the top of the scope". It has nothing to do with the variable existing, having memory allocated for it, or being initialised.
A declaration just says that something exists. In JavaScript you can declare variables, functions and (more recently) classes.
In some languages (e.g. C, C++) it's possible to declare something without defining it. For example:
// this declares a function exists with a given signature, but doesn't define its implementation
void someFunction();
someFunction(); // here we call the function, since we know it exists
// here we define the function, which we have to do at some point
void someFunction() { /* ... */ }
This pattern is less common in modern languages, where the declaration and the definition tends to be combined, but it's useful to understand the distinction seeing as your question seems largely about terminology.
Variables can be declared, however they don't have definitions.
let b; // we declare that there's a variable 'b'
Instead you can assign a variable:
b = 5; // assignment
let c = 6; // declaration and assignment in one statement
The concept of binding in computer science has many forms. For example, when you type foo in your code, binding is the act of working out which variable/function/type/... should be used. In JavaScript this is pretty straightforward, but in some languages it can get pretty hairy (due to things like overload resolution and so forth).
However I don't believe that's what MDN means when they talk about let bindings. I believe it's a shorthand for "let declaration and assignment", as we saw above.
Regardless, I wouldn't worry too much about that term. The most important bit to understand from the paragraph you've quoted is that let and const are tighter versions of var, introduced in recent versions of the language to address pitfalls and surprises that came from the way var works.
Previously I thought the variable keyword and variable name together comprised a declaration
You're right.
var a;
var b = 1;
let c;
let c = 2;
const d = 3;
These are all declarations of variables (even though const technical variables can't vary, or more precisely, they cannot be reassigned).
It's just that var is a bit sloppy and surprising.
You could declare a var more than once within the same scope:
var a = 1;
var a = 2;
This won't work with let:
let a = 1;
let a = 2; // SyntaxError: Identifier 'a' has already been declared
Scoping on var can be surprising too:
for (var i = 0; i < 10; i++)
{
var inner = 1;
}
console.log(inner); // prints 1 even though you might think this would be an error
Or worse:
for (var i = 0; i < 10; i++)
{
for (var i = 0; i < 10; i++)
{
console.log('hello');
}
}
At a glance you might think this would print hello 100 times (10*10), but actually it is only printed 10 times because both loops use the same variable. This is a type of programmer error that the language should really prevent. If that code used let i instead, it would produce a syntax error.
As for hoisting you can think of it as though all the var declarations were moved to the top of the containing function.
function foo()
{
doThing();
var i = 0;
doSomethingElse();
for (var j = 0; j < 10; j++)
{
var k = 10;
}
}
Even though that's how you might write the code, it behaves as though you had written:
function foo()
{
var i; // all declarations hoisted to top of containing function scope
var j;
var k;
doThing();
i = 0;
doSomethingElse();
for (j = 0; j < 10; j++)
{
k = 10;
}
}
This is why you can write:
i = 10;
var i;
The var is moved up in the code, so it behaves as:
var i;
i = 10;
You can think of let as not being moved. Therefore it is an error to reference it before it is declared.
The main thing to understand here is that the js engine actually visits a let statement inntwo different situations (as well as every other statement, but it particularily matters here). It is visited once during parsing, when it generates an AST and also analyzes the scopes and the variables. It also creates a list of variables for each scope. Now when the code gets executed, the engine visits the statement a second time (or more often if its inside a loop / function / whatever) and now finally initializes the variable and assigns a value to it. So "hoisting" is basically just caused because of the parsing / executing stages, the engine knows that a variable exists before it reaches the declaration statement during execution as it has already parsed it before.
Is the "let binding" referrred to (the hoisting of let and const) just the keyword let, or is it just the creation of storage space (which doesn't have to do with the keyword)?
The keyword actually causes an entry in the scope record, which will then get turned into a storage space during execution. On the other hand the statement itself causes an initialization during execution. So its actually hard to say when a declaration happens, thats a question of words. Its common to say
That variable was declared at line 10
Its declared in that block
so wether "declaration" refers to the statement or the scope assignment is up to you :)
the answerer said they are actually an initialization.
Actually the answerer prefered to call it "initialization" and not "declaration" to not confuse readers, but well in reality its confusing as human languages are not as clearly defined as machine ones.
It may seem very trivial issue but very confusing and recurring for me. In some manuals for javascript or tutorials these terms are used alternately.
In others I found the explanation that we declare variables when we create them with var const let and we define variables, when we append some value/object to the declared variable as below:
var name; //declaring
name = 'Adam' //defining
var age = 'dead' //declaring + defining
Are there any approved and correct rules of using these two terms?
I'd say that "variable definition" is not a standard JavaScript term.
Functions (of all kinds) and object properties can get defined, but variables always get declared. This terminology might hint at the declarative nature of variables - a declaration always applies to the complete current scope, it's not an action that gets executed and does something.
var name is a declaration. var age = 'dead' is a declaration with an initialiser. name = 'Adam' is just an assignment. I'd guess that "defining" a variable refers to it no longer being undefined, so both an assignment statement or the initialiser of the declaration might do that. I'd rather speak of the initialisation of the variable, though.
var x is a declaration because you are not defining what value it holds but you are declaring its existence and the need for memory allocation.
var x = 1 is both declaration and definition but are separated with x being declared in the beginning while its definition comes at the line specified (variable assignments happen inline).
I see that you already understand the concept of hoisting but for those that don't, Javascript takes every variable and function declaration and brings it to the top (of its corresponding scope) then trickles down assigning them in order.
You seem to know most of this already though. Here's a great resource if you want some advanced, in-depth exploration. Yet I have a feeling you've been there before.
Javascript Garden
In this example why does pushing the function reference onto the array not change the scope execution context of this whereas assigning the function reference to a new variable does change the scope execution context of this?
(function() {
function Car(year) {
this.year = year;
}
Car.prototype = {
logYear: function() {
console.log(this.year);
}
};
var ford = new Car('Ford', 1999);
ford.logYear();
var cbs = [];
cbs.push(ford.logYear);
for(var x = 0; x < cbs.length; x++) {
cbs[x](); // -> 1999 #1
var callback = cbs[x];
callback(); // -> undefined #2
}
})()
Is this because the reference to the function in the array points to the original function on the ford object where this is still defined as the instance (#1) and the variable assignment changes the this to point to the wrapping IIFE block (#2)?
Is this a good pattern if I need to collect of bunch of methods like this from various objects and call them somewhere else?
How does this referential calling relate to examples like console.error.bind(console)?
Thanks!
-- Update
Thanks to #Satyajeet for the nice explanation and clarification.
Typos & copying errors aside the reason I was asking this question in the first place is that I suspected what Satyajeet confirmed but an application I am working on does not reflect this behavior (or so I thought).
It turns out that in the application I am performing a similar process to the above code where I call cbs.push(ford.logYear);, adding multiple methods from different objects to an array.
At a point in the app I call all these methods and expect them to behave in the same way as when they are called in the execution context scope of the original object... and they do, because the values the methods interact with are not attached to this, they are captured in closures.
See example plunker here
-- Update 2
Fixed usage of execution context and scope to be accurate for each part of the question/answer.
Ignoring your late night copy paste mistake, and redefining your Car function to
function Car(name, year) {
this.name = name;
this.year = year
}
#1 indeed more of a question about how Array works rather then about the context and scope(*#2)
You are calling a function inside an array, So in javascript each element of an array is a property of that Array Object. for example
var a = [];
a.push('Some value'); // a.0 is a property
but you just can not call a.0 because in javascript properties that begin with a digit cannot be referenced with dot notation, and must be accessed using bracket notation
So when you are calling cbx[0]() it is essentially same as cbx.0().
And here comes the role of Scope and Execution context in javascript. There are already many good articles and answers about Scope and Context in javascript. Just like this, So i think its not worth to explain all that here.
But fundamentally this is not defined till the execution of function(this depends on Execution context rather then scope).
So your #1 will print undefined because cbs[0]() is equivalent to cbs.0(), And this(Execution context) is set to Array itself, which is [function]. (You only have a function inside it).
And your #2 will also print undefined because Execution context is global(window object in case of browser) there.
Answer to your 3rd question is, You need to Explicitly hard bind Execution context to your function.
cbs.push(ford.logYear.bind(ford));
And your 4th question is i think just an another use case of ES5's bind method, Nothing special. It is normally used because browser implementations requires that execution context(this) of console.error must be set to window.console.
I've recently come across the const keyword in JavaScript. From what I can tell, it is used to create immutable variables, and I've tested to ensure that it cannot be redefined (in Node.js):
const x = 'const';
const x = 'not-const';
// Will give an error: 'constant 'x' has already been defined'
I realise that it is not yet standardized across all browsers - but I'm only interested in the context of Node.js V8, and I've noticed that certain developers / projects seem to favor it heavily when the var keyword could be used to the same effect.
When is it appropriate to use const in place of var?
Should it be used every time a variable which is not going to be
re-assigned is declared?
Does it actually make any difference if var is used in place of
const or vice-versa?
There are two aspects to your questions: what are the technical aspects of using const instead of var and what are the human-related aspects of doing so.
The technical difference is significant. In compiled languages, a constant will be replaced at compile-time and its use will allow for other optimizations like dead code removal to further increase the runtime efficiency of the code. Recent (loosely used term) JavaScript engines actually compile JS code to get better performance, so using the const keyword would inform them that the optimizations described above are possible and should be done. This results in better performance.
The human-related aspect is about the semantics of the keyword. A variable is a data structure that contains information that is expected to change. A constant is a data structure that contains information that will never change. If there is room for error, var should always be used. However, not all information that never changes in the lifetime of a program needs to be declared with const. If under different circumstances the information should change, use var to indicate that, even if the actual change doesn't appear in your code.
2017 Update
This answer still receives a lot of attention. It's worth noting that this answer was posted back at the beginning of 2014 and a lot has changed since then. ecmascript-6 support is now the norm. All modern browsers now support const so it should be pretty safe to use without any problems.
Original Answer from 2014
Despite having fairly decent browser support, I'd avoid using it for now. From MDN's article on const:
The current implementation of const is a Mozilla-specific extension and is not part of ECMAScript 5. It is supported in Firefox & Chrome (V8). As of Safari 5.1.7 and Opera 12.00, if you define a variable with const in these browsers, you can still change its value later. It is not supported in Internet Explorer 6-10, but is included in Internet Explorer 11. The const keyword currently declares the constant in the function scope (like variables declared with var).
It then goes on to say:
const is going to be defined by ECMAScript 6, but with different semantics. Similar to variables declared with the let statement, constants declared with const will be block-scoped.
If you do use const you're going to have to add in a workaround to support slightly older browsers.
For why to use const, Tibos's answer's great.
But you said:
From what I can tell, it is used to create immutable variables
That is wrong. Mutating a variable is different from reassigning:
var hello = 'world' // Assigning
hello = 'bonjour!' // Reassigning
With const, you can not do that:
const hello = 'world'
hello = 'bonjour!' // Error
But you can mutate your variable:
const marks = [92, 83]
marks.push(95)
console.log(marks) // [92, 83, 95] -> the variable has been mutated.
So, any process that changes the variable's value without using the = sign is mutating the variable.
Note: += for example is ... reassigning!
var a = 5
a += 2 // Is the same as a = a + 2
So, the bottom line is: const doesn't prevent you from mutating variables; it prevents you from reassigning them.
To integrate the previous answers, there's an obvious advantage in declaring constant variables, apart from the performance reason: if you accidentally try to change or redeclare them in the code, the program will respectively not change the value or throw an error.
For example, compare:
// Will output 'SECRET'
const x = 'SECRET'
if (x = 'ANOTHER_SECRET') { // Warning! Assigning a value variable in an 'if' condition
console.log (x)
}
with:
// Will output 'ANOTHER_SECRET'
var y = 'SECRET'
if (y = 'ANOTHER_SECRET') {
console.log (y)
}
or
// Will throw TypeError: const 'x' has already been declared
const x = "SECRET"
/* Complex code */
var x = 0
with
// Will reassign y and cause trouble
var y = "SECRET"
/* Complex code */
var y = 0
const is not immutable.
From the MDN:
The const declaration creates a read-only reference to a value. It
does not mean the value it holds is immutable, just that the variable
identifier cannot be reassigned.
var: Declare a variable. Value initialization is optional.
let: Declare a local variable with block scope.
const: Declare a read-only named constant.
Example:
var a;
a = 1;
a = 2; // Reinitialize possible
var a = 3; // Re-declare
console.log(a); // 3
let b;
b = 5;
b = 6; // Reinitialise possible
// let b = 7; // Redeclare not possible
console.log(b);
// const c;
// c = 9; // Initialization and declaration at the same place
const c = 9;
// const c = 9; // Redeclare and initialization is not possible
console.log(c); // 9
// NOTE: Constants can be declared with uppercase or lowercase, but a common
// convention is to use all-uppercase letters.
You have great answers, but let's keep it simple.
const should be used when you have a defined constant (read as: it won't change during your program execution).
For example:
const pi = 3.1415926535
If you think that it is something that may be changed on later execution then use a var.
The practical difference, based on the example, is that with const you will always assume that pi will be 3.14[...], it's a fact.
If you define it as a var, it might be 3.14[...] or not.
For a more technical answer, Tibos' is academically right.
In my experience, I use const when I want to set something I may want to change later without having to hunt through the code looking for bits that have been hard coded, e.g., a file path or server name.
The error in your testing is another thing though. You are trying to make another variable called x, and this would be a more accurate test:
const x = 'const';
x = 'not-const';
Personal preference really. You could use const when, as you say, it will not be re-assigned and is constant. For example if you wanted to assign your birthday. Your birthday never changes so you could use it as a constant. But your age does change so that could be a variable.
Summary:
const creates an immutable binding, meaning a const variable identifier is not reassignable.
const a = "value1";
You cannot reassign it with
a = "value2";
However, if the const identifier holds an object or an array, the value of it can be changed as far as we are not reassigning it.
const x = { a: 1 }
x.a = 2; // Is possible and allowed
const numbers = [1, 2];
numbers.push(3); // Is possible and allowed
Please note that const is a block-scoped just like let which is not same as var (which is function-scoped).
In short, when something is not likely to change through reassignment use const, else use let or var, depending on the scope you would like to have.
It's much easier to reason about the code when it is dead obvious what can be changed through reassignment and what can't be. Changing a const to a let is dead simple. And going const by default makes you think twice before doing so. And this is in many cases a good thing.
The semantics of var and let
var and let are a statement to the machine and to other programmers:
I intend that the value of this assignment change over the course of execution. Do not rely on the eventual value of this assignment.
Implications of using var and let
var and let force other programmers to read all the intervening code from the declaration to the eventual use, and reason about the value of the assignment at that point in the program's execution.
They weaken machine reasoning for ESLint and other language services to correctly detect mistyped variable names in later assignments and scope reuse of outer scope variable names where the inner scope forgets to declare.
They also cause runtimes to run many iterations over all codepaths to detect that they are actually, in fact, constants, before they can optimise them. Although this is less of a problem than bug detection and developer comprehensibility.
When to use const
If the value of the reference does not change over the course of execution, the correct syntax to express the programmer's intent is const. For objects, changing the value of the reference means pointing to another object, as the reference is immutable, but the object is not.
"const" objects
For object references, the pointer cannot be changed to another object, but the object that is created and assigned to a const declaration is mutable. You can add or remove items from a const referenced array, and mutate property keys on a const referenced object.
To achieve immutable objects (which again, make your code easier to reason about for humans and machines), you can Object.freeze the object at declaration/assignment/creation, like this:
const Options = Object.freeze(['YES', 'NO'])
Object.freeze does have an impact on performance, but your code is probably slow for other reasons. You want to profile it.
You can also encapsulate the mutable object in a state machine and return deep copies as values (this is how Redux and React state work). See Avoiding mutable global state in Browser JS for an example of how to build this from first principles.
When var and let are a good match
let and var represent mutable state. They should, in my opinion, only be used to model actual mutable state. Things like "is the connection alive?".
These are best encapsulated in testable state machines that expose constant values that represent "the current state of the connection", which is a constant at any point in time, and what the rest of your code is actually interested in.
Programming is already hard enough with composing side-effects and transforming data. Turning every function into an untestable state machine by creating mutable state with variables just piles on the complexity.
For a more nuanced explanation, see Shun the Mutant - The case for const.
The main point is that how to decide which one identifier should be used during development.
In JavaScript here are three identifiers.
var (Can redeclared and reinitialize)
const (Can't redeclared and reinitialize, and can update array values by using push)
let (can reinitialize, but can't redeclare)
'var': At the time of coding when we talk about code standards, then we usually use the name of an identifier which is one that is easy to understand by other users and developers.
For example, if we are working thought many functions where we use some input and process this and return some result, like:
Example of variable use
function firstFunction(input1, input2)
{
var process = input1 + 2;
var result = process - input2;
return result;
}
function otherFunction(input1, input2)
{
var process = input1 + 8;
var result = process * input2;
return result;
}
In above examples both functions producing different-2 results, but using same name of variables. Here we can see 'process' & 'result' both are used as variables and they should be.
Example of constant with variable
const tax = 10;
const pi = 3.1415926535;
function firstFunction(input1, input2)
{
var process = input1 + 2;
var result = process - input2;
result = (result * tax)/100;
return result;
}
function otherFunction(input1, input2)
{
var process = input1 + 8;
var result = process * input2 * pi;
return result;
}
Before using 'let' in JavaScript we have to add ‘use strict’ on the top of the JavaScript file
Example of let with constant & variable
const tax = 10;
const pi = 3.1415926535;
let trackExecution = '';
function firstFunction(input1, input2)
{
trackExecution += 'On firstFunction';
var process = input1 + 2;
var result = process - input2;
result = (result * tax)/100;
return result;
}
function otherFunction(input1, input2)
{
trackExecution += 'On otherFunction'; # Can add current time
var process = input1 + 8;
var result = process * input2 * pi;
return result;
}
firstFunction();
otherFunction();
console.log(trackExecution);
In above example you can track which one function executed when & which one function not used during specific action.
First, three useful things about const (other than the scope improvements it shares with let):
It documents for people reading the code later that the value must not change.
It prevents you (or anyone coming after you) from changing the value unless they go back and change the declaration intentionally.
It might save the JavaScript engine some analysis in terms of optimization. E.g., you've declared that the value cannot change, so the engine doesn't have to do work to figure out whether the value changes so it can decide whether to optimize based on the value not changing.
Your questions:
When is it appropriate to use const in place of var?
You can do it any time you're declaring a variable whose value never changes. Whether you consider that appropriate is entirely down to your preference / your team's preference.
Should it be used every time a variable which is not going to be re-assigned is declared?
That's up to you / your team.
Does it actually make any difference if var is used in place ofconst` or vice-versa?
Yes:
var and const have different scope rules. (You might have wanted to compare with let rather than var.) Specifically: const and let are block-scoped and, when used at global scope, don't create properties on the global object (even though they do create globals). var has either global scope (when used at global scope) or function scope (even if used in a block), and when used at global scope, creates a property on the global object.
See my "three useful things" above, they all apply to this question.
It provides:
a constant reference, e.g., const x = [] - the array can be modified, but x can't point to another array; and
block scoping.
const and let will together replace var in ECMAScript 6/2015. See discussion at JavaScript ES6 Variable Declarations with let and const
When it comes to the decision between let and const (both block scoped), always prefer const so that the usage is clear in the code. That way, if you try to redeclare the variable, you'll get an error. If there's no other choice but redeclare it, just switch for let. Note that, as Anthony says, the const values aren't immutable (for instances, a const object can have properties mutated).
When it comes to var, since ES6 is out, I never used it in production code and can't think of a use case for it. One point that might consider one to use it is JavaScript hoisting - while let and const are not hoisted, var declaration is. Yet, beware that variables declared with var have a function scope, not a block scope («if declared outside any function, they will be globally available throughout the program; if declared within a function, they are only available within the function itself», in HackerRank - Variable Declaration Keywords). You can think of let as the block scoped version of var.
'const' is an indication to your code that the identifier will not be reassigned.
This is a good article about when to use 'const', 'let' or 'var': JavaScript ES6+: var, let, or const?
I am not an expert in the JavaScript compiling business, but it makes sense to say, that V8 makes use of the const flag.
Normally after declaring and changing a bunch of variables, the memory gets fragmented, and V8 is stopping to execute, makes a pause some time of a few seconds, to make garbage collection, or garbage collection.
If a variable is declared with const, V8 can be confident to put it in a tightly fixed-size container between other const variables, since it will never change.
It can also save the proper operations for that datatypes since the type will not change.
My opinions:
Q. When is it appropriate to use const in place of var?
A. Never!
Q: Should it be used every time a variable which is not going to be re-assigned is declared?
A: Never! Like this is going to make a dent in resource consumption...
Q. Does it actually make any difference if var is used in place of const or vice-versa?
A: Yes! Using var is the way to go! Much easier in dev tools and save from creating a new file(s) for testing. (var in not in place of const - const is trying to take var's place...)
Extra A: Same goes for let. JavaScript is a loose language - why constrict it?!?