Contrasting var and ES6s new declarations: let and const
  let and const are two new declaration types in JavaScript, which
  have the ability to completely replace var declaration. To use them
  effectively, and understand why they can be a direct replacement,
  it's important to understand how they work.
  var is function scoped. It is hoisted and initialized at the top
  var, regardless of where it is assigned, will become declared
  and initialized at the beginning of the function. This means that any variable you
  declare will be available everywhere inside the function. This process is referred to as hoisting.
  Hoisted variables with var are declared and initialized at
  the top of the function, but have no value
  All variables that are declared and initialized with var
  are initialized as undefined. They have no value until you
  reach the line of code that assigns it a value.
const undefinedConsoleLog = _ => {
  console.log(sadlyUndefined) //undefined
  var sadlyUndefined = 'declared by var, undefined where I console log'
  var isDefined = 'value assigned before console log'
  console.log(isDefined) //'value assigned before console log'
}
  let and const is block scoped
This means that variable declaration [appears] to not be hoisted. A big win. But this big win requires you to know exactly what a "block" is, or you will get into trouble in places that seem counterintuitive.
const failedResponse = _ => {
  if ('this is a block'){
    let response = 'yes, this is a block'
    console.log(response) //'yes, this is a block'
  }
  console.log(response) //throws an error
}
  Why? Because my if statement is considered a block.
  response is only available inside my if
  statement. Anything with nested curly braces is considered a block.
How do I fix my failedResponse function scoping issue?
Easy. Change where the variable is declared. A scope is itself and every nested block it contains.
const fixedResponse = _ => {
  let response //declared, and then initialized as undefined
  console.log(response) //undefined
  if ('this is a block') {
    response = 'yes, this is a block'
    console.log(response) //'yes, this is a block'
  }
  console.log(response) //'yes, this is a block'
}
  Declaration and initialization are distinct concepts in let and const
  I keep using a word you probably have not seen when people talk
  about hoisting: initialization. Declaration and initialization are not
  the same. Variables are always declared at the top. But let and
  const, they are not initialized (unless they are already at the top).
  This is how let and const become block scoped. Allocation of memory (hoisting)
  always occurs. It is fundamental to the JavaScript engine and will never go away.
  But the initialization process is different. You cannot
  use variables that are not initialized. var is initialized as undefined,
  let and const throw an error because they are not initialized.
const hoistedAndInitialized = _ => {
  console.log(initializedVar) //undefined
  var initializedVar = 'declared and initialized as undefined on top'
}
const hoistedButNotInitialized = _ => {
  console.log(uninitializedLet) //ReferenceError: uninitializedLet is not defined
  let uninitializedLet = 'declared at the top, but not initialized. will throw error'
}
  Replacing var in any situation
Function and block scoping are fundamentally different, but there's nothing stopping you from making the declared block as the entire function.
const alwaysFunctionScoped = _ => {
  if ('I use var') {
    var text = 'I am available anywhere in the function'
  }
  console.log(text) //'I am available anywhere in the function'
}
const alsoFunctionScoped = _ => {
  let text
  if ('I use let') {
    text = 'I have already been hoisted and initialized.
    function scope === block scope'
  }
  console.log(text) //'I have already been hoisted and initialized.
  // function scope === block scope'
}
  But be careful with let and const...
  If I declare text inside my if statement, they are now different variables.
  They might as well be completely different variable names.
const innerTextIsNowBlockScopedAgain = _ => {
  let text
  if ('I declare with let inside this block') {
    let text = 'exists inside this inner scope only.'
  }
  console.log(text) //undefined
}
Comments
Post a Comment