---
# System prepended metadata

title: JavaScript核心篇 - var、let、const的差異

---

---
title: JavaScript核心篇 - var、let、const的差異
tags:
description:
---
JavaScript核心篇 - var、let、const的差異
---

### `var`有==向上提升Hoisting==特性
從下面例子了解到，var具有向上提升特性:point_right: [JavaScript核心篇 - Hoisting](/oNFdxQ71SP-7Q4K_NVaerw)
```javascript=
console.log(a);
var a = 1;
console.log(a);
```
實際運行上是這樣
```javascript=
var a; //先定義好var a，未賦予任何值
console.log(a); // undefinde

a = 1; // 把1賦予給a
console.log(a); // 1
```
`let`、`const`==沒有向上提升（Hoisting）特性==，在哪一行成立就在哪一行建立參數，然後賦值一並完成。

在未定義`let a`之前，第一行程式碼`console.log(a)`是找不到`let a`的

`let`、`const`用在宣告區塊(作用域)內的變數，沒有向上提升（Hoisting）特性，==不會影響全域變數==。
```javascript=
var a = 0;
function data(){
	const a = 1; //只在區塊{}內使用
	console.log(a); // 取到const a的值
}

data();
console.log(a); // 取到var a的值
```
<br>

### `let`、`const`不會出現在全域
從下面例子得知：

```javascript=
var a = 'ken'; 
let b = 'john';
c = 'joe';
console.log(window);
console.log(window.a);    // ken
console.log(window.b);    // undefined
console.log(window.c);    // jeo
```
- `var a` **有Hoisting特性**，在全域物件`window`下**能看到**。
- `let a` **沒有Hoisting特性**，在全域物件`window`下**看不到**。
- `c = 'joe'`**沒有宣吿**，在全域物件`window`下，只是**全域屬性**。

![](https://i.imgur.com/24at2Y6.png)

- 屬性能被**刪除**，已宣告的變數**無法被刪除**
```javascript=
var a = 'ken'; 
let b = 'john';
c = 'joe';

delete window.a;
delete window.c;

console.log(window.a);    // ken
console.log(window.b);    // undefined
console.log(window.c);    // undefined
```
<br>

### 作用域
:::info
var是**函式作用域**，let、const是**block**、**script作用域**。
在**function裡宣告的變數**，其作用域就**只在**該函式內。
:::
變數只能==內層往外層查找==，**無法**外層往內層查找。

- `fn1()`執行後，`console.log()`除了印出本身大括號的`var b`，還往外層作用域（全域window）尋找`var a`。
- `fn2()`執行後，`console.log()`除了往外一層作用域（`fn1()`）尋找`var b`，還往**最外層**（全域window）作用域尋找`var a`後，`console.log()`印出結果。
```javascript=
var a = '小明';

function fn1() {
  var b = '大頭';
  console.log(a, b);    // 小明 大頭

  function fn2() {
    console.log(a, b);    // 小明 大頭
  }
  fn2();
}
fn1();
```
<br>

#### `fn2()`的`console.log(b)`取得到值？
- 在`fn1()`未宣告變數`b`，只是增加全域物件window屬性`b = '大頭'`。
- 在`fn2()`的`console.log(window)`，在全域物件window下可以看到屬性`b`。
:::success
全域物件屬性在**任何環境**下都能存取到
:::
- `fn2()`的函式作用域內，找不到變數`b`，便會向外層全域物件window尋找到屬性`b`。

 ![](https://i.imgur.com/Is8Xg8h.png)

```javascript=
var a = '小明';

function fn1() {
  b = '大頭';
};
function fn2() {
  console.log(b);
  console.log(window);
};
fn1();
fn2();
```
<br>

#### `var`跟`let`、`const`作用域的不同
- var
```javascript=
for (var index = 0; index < 10; index++) {
  console.log (index);
};
```
- let
```javascript=
for (let index = 0; index < 10; index++) {
  console.log (index);
};
```
`for迴圈`的判斷式，不管是用`var`、`let`，得到的結果都會是
```
0
1
2
3
4
5
6
7
8
9
```
把`console.log (index)`移出大括號，得到的結果是10。（迴圈結束時，還會執行一次`index++`）。:point_right: [let、const的實戰運用](/XOoouAA_TlSeTMa9xt0AdQ)
- 因為for迴圈執行時，index會在大括號內，值會不斷被覆蓋。
- 最後for迴圈執行完，`console.log (index)`取到的值，會是全域變數`index`的值。

```javascript=
for (var index = 0; index < 10; index++) {

};
console.log (index);
```
因為let是**block區塊作用域**，因此在全域下是取不到`index`的值。
```javascript=
for (let index = 0; index < 10; index++) {

};
console.log (index);
```
#### 語法作用域

:::success
就是看程式碼怎麼寫的，來決定作用域。
:::
**下面範例`console.log()`執行的結果是？**

- `fn2()`執行，依序到`fn1()`執行時就直接往外層找`var name = '小智'`
```javascript=
var name = '小智';

function fn1() {
  console.log (name);    // 小智
}

function fn2() {
  var name = 'pikachu';
  fn1();
}

fn2();
```
**把程式碼修改一下，`console.log()`執行的結果是？**
- fn2()運行，重新賦予`'pikachu'`給外層全域變數`name`。
- 等到fn1()運行，`console.log()`往外層找全域變數`name`，印出`pikachu`。
```javascript=
var name = '小智';

function fn1() {
  console.log (name);    // pikachu
}

function fn2() {
  name = 'pikachu';
  fn1();
}

fn2();
```
