# let 和 const 声明常见概念

## 作用域(Scope)是什么

作用域是程序的执行环境，它包含了在当前位置可访问的变量和函数。在 ES5 时代，我们有全局作用域和局部作用域，ES6 则新增了块级作用域。 全局作用域是最外层的作用域，在函数外面定义的变量属于全局作用域，可以被任何其他子作用域访问。在浏览器中，window 对象就是全局作用域。 局部作用域的基本单元是 function。局部作用域是在函数内部的作用域。在局部作用域定义的变量只能在该作用域以及其子作用域被访问。 var、const、let 则是关键字，我们将这三个关键字作为作用域的声明变量。

## var 声明

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

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

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

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

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

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

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

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

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

还有一个例子:

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

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

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

趣题:

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

## let 与 const 声明

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

### let 声明

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

```js
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声明的变量，其值不可更改。准确地说它不可以被重新赋值，但是可以更改。

```js
  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}
```

### 常见例子

```js
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(); 你可以将作用域想象成一系列不断变小的门。如果一个个子不高的人可以穿过最小的门(局部最小作用域)，那么必然可以穿过任何比它大的门(外部作用域)。

let和const不会被提升。

以下是一些常见的题目：

```js

{  /* 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 关键字声明的变量将会绑定到全局作用域上。

```js
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'
```

```js
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, 这样就可以在某种程度上实现代码的不可变。从而防止某些错误的产生。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://shenjunhong.gitbook.io/blog/js/es6-zhi-let-he-const-chang-jian-gai-nian.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
