ES6之 let 和 const 声明见解

1,482 阅读5分钟

let 和 const 声明常见概念

作用域(Scope)是什么

作用域是程序的执行环境,它包含了在当前位置可访问的变量和函数。在 ES5 时代,我们有全局作用域和局部作用域,ES6 则新增了块级作用域。

全局作用域是最外层的作用域,在函数外面定义的变量属于全局作用域,可以被任何其他子作用域访问。在浏览器中,window 对象就是全局作用域。

局部作用域的基本单元是 function。局部作用域是在函数内部的作用域。在局部作用域定义的变量只能在该作用域以及其子作用域被访问。

var、const、let 则是关键字,我们将这三个关键字作为作用域的声明变量。

var 声明

局部 JavaScript 变量

var 声明的变量总是归属于包含函数(即全局,如果在最顶层的话)。在 JavaScript 函数内部声明的变量(使用 var)是局部变量,所以只能在函数内部访问它。(该变量的作用域是局部的)。您可以在不同的函数中使用名称相同的局部变量,因为只有声明过该变量的函数才能识别出该变量。

提升(Hoisting)

在编译过程中,将var和function的定义移动到他们作用域最前面的行为叫做提升。 整个函数定义会被提升。所以,你可以在函数还未定义之前调用它,而不用担心找不到该函数。

console.log(toSquare(3));  // 9

function toSquare(n){
  return n*n;
}

变量只会被部分提升。而且只有变量的声明会被提升,赋值不会动。

开发者可能最希望实现 for 循环的块级作用域了,因为可以把随意声明的计数器变量限制在循环内部。

  for(var i = 0; i< 10; i++>){
    console.log(i)
  }

立即执行函数能够有效解决:

for(var i = 0; i< 10; ++i){
  (function(value){
     console.log(value)
  }(i))
}

还有一个例子

    (function() {
      var testValue = 'hello';
      var testFunc = function () {
        console.log('just test');
      };
    })();

    console.log(window.testValue);// undefined

    console.log(window.testFunc);// undefined

趣题:

var x = 10,
  y = 20;
[y, x] = [x, y]
console.log(x, y)

let 与 const 声明

ES6 的 let 和 const 都是新引入的关键字。它们不会被提升,而且是块作用域。也就是说被大括号包围起来的区域声明的变量外部将不可访问。

let 声明

过早访问 let 声明的引用导致的这个 referenceerror 叫做临时死亡区错误.你在访问一个已经声明但还没有初始化的变量. 创建一个块作用域.

let g1 = 'global 1'
let g2 = 'global 2'
{   /* Creating a new block scope */
  g1 = 'new global 1'
  let g2 = 'local global 2'
  console.log(g1)   // 'new global 1'
  console.log(g2)   // 'local global 2'
  console.log(g3)   // ReferenceError: g3 is not defined
  let g3 = 'I am not hoisted';
}
console.log(g1)    // 'new global 1'
console.log(g2)    // 'global 2'

const 声明

const 是对赋值做锁定,不对值的改变锁定。例如:数组、对象。 一个常见的误解是:使用const声明的变量,其值不可更改。准确地说它不可以被重新赋值,但是可以更改。

  const tryMe = 'initial assignment';
  tryMe = 'this has been reassigned';  // TypeError: Assignment to constant variable.
  // You cannot reassign but you can change it…
  const array = ['Ted', 'is', 'awesome!'];
  array[0] = 'Barney';
  array[3] = 'Suit up!';
  console.log(array);     // [“Barney”, “is”, “awesome!”, “Suit up!”]
  const airplane = {};
  airplane.wings = 2;
  airplane.passengers = 200;
  console.log(airplane);   // {passengers: 200, wings: 2}

常见例子

function outer() {
  let a = 1;
  function inner() {
    let b = 2;
    function innermost() {
      let c = 3;
      console.log(a, b, c);   // 1 2 3
    }
    innermost();
    console.log(a, b);        // 1 2 — 'c' is not defined
  }
  inner();
  console.log(a);             // 1 — 'b' and 'c' are not defined
}

outer(); 你可以将作用域想象成一系列不断变小的门。如果一个个子不高的人可以穿过最小的门(局部最小作用域),那么必然可以穿过任何比它大的门(外部作用域)。

以下是一些常见的题目:


{  /* Original code */
  console.log(i);  // undefined
  var i = 10
  console.log(i);  // 10
}

{  /* Compilation phase */
  var i;
  console.log(i);  // undefined
  i = 10
  console.log(i);  // 10
}
// ES6 let & const
{
  console.log(i);  // ReferenceError: i is not defined
  const i = 10
  console.log(i);  // 10
}
{
  console.log(i);  // ReferenceError: i is not defined
  let i = 10
  console.log(i);  // 10
}

变量:var,let和const

在ES6之前,只能使用var来声明变量。在一个函数体中声明的变量和函数,周围的作用域内无法访问。在块作用域if和for中声明的变量,可以在if和for的外部被访问。

注意:如果没有使用 var,let 或者 const 关键字声明的变量将会绑定到全局作用域上。

function greeting() {
  console.log(s) // undefined
  if(true) {
    var s = 'Hi';
    undeclaredVar = 'I am automatically created in global scope';
  }
  console.log(s) // 'Hi'
}
console.log(s);  // Error — ReferenceError: s is not defined
greeting();
console.log(undeclaredVar) // 'I am automatically created in global scope'
let a = 2;

if(a> 1){
  let b = a +1;
  console.log(b)  //6

  for(let i = a; i <=b;i ++){
    let j = i +10;
    console.log(j)
  }
  //12 13 14 15 16

  let c = a+ b;
  console.log('c: ', c);
}

总结

默认使用 const, 只在确实需要改变的时候使用 let, 这样就可以在某种程度上实现代码的不可变。从而防止某些错误的产生。