對塊作用域與變數函式提升再添新認識
阿新 • • 發佈:2021-03-12
[toc]
# 關於這篇部落格
這篇部落格是在我讀《你不知道的JavaScript-上卷》的時候,遇到的我覺得需要記錄下來的知識。
剛好又能夠配合之前我寫的這篇[執行上下文與執行上下文棧部落格](https://www.cnblogs.com/fitzlovecode/p/jsadvanced7.html#%E5%8F%98%E9%87%8F%E6%8F%90%E5%8D%87%E4%B8%8E%E5%87%BD%E6%95%B0%E6%8F%90%E5%8D%87%E7%9A%84%E4%BC%98%E5%85%88%E7%BA%A7)中關於變數提升與函式提升知識,可以認為是對其的補充或新的認識吧,那麼本篇開始!
## 回憶塊與塊級作用域
塊我這裡指的是程式碼塊,在我學JavaScript無論是初級部分還是高階部分的時候,我都被教或者自己認為, `{}`對普通程式碼(除函式、類外)是沒有任何影響的,至少在ES6以前是這樣子的
``` js
var a = 666
{
console.log(a) // 666
function foo () {
console.log('foo()')
}
var myName = 'Fitz'
}
foo() // 'Foo()'
console.log(myName) // 'Fitz'
```
看起來沒有任何影響,一切都是那麼的和諧對吧,但事情就出在了==我在測試變數、函式提升與塊級作用域配合時==
直接附上
``` js
console.log(a) // 猜猜是啥
foo() // 猜猜是啥
{
var a = 666
function foo () {
console.log('foo()')
}
}
```
根據我以往的認識,`{}`在這是不會影響任何東西的,所以根據執行上下文與執行上下文棧所造成的的變數提升與函式提升,這個程式碼最終執行的結果應該是:
``` js
console.log(a) // undefined
foo() // 'foo()'
{
var a = 666
function foo () {
console.log('foo()')
}
}
```
==可真正的執行結果是:==
``` js
console.log(a) // undefined
console.log(foo) // 'undefined'
foo() // TypeError: foo is not a function
{
var a = 666
function foo () {
console.log('foo()')
}
}
```
這就說明`{}`在這起作用了,最起碼它阻擋了`foo函式`的提升,但是這個阻擋又是不全面的,至於為什麼我這麼認為,等等再說,先看看當前是怎麼回事
由於`var`符合之前的知識,所以這裡我們就不再關心了
根據《你不知道的JavaScript-上卷》書上說道,造成foo()提前執行報錯,而不像之前執行上下文與執行上下文棧表現的那樣,是因為==一個普通塊內部的函式申明會被提升到所在作用域(這裡就是這個塊級作用域)的頂部==, 雖然不保證後續是否還會這樣,但是至少到ES10了還是這樣,所以記錄一下
所以上面的程式碼是這樣的
``` js
console.log(foo) // 'undefined'
foo() // TypeError: foo is not a function
{
// 限制在這
function foo () {
console.log('foo()')
}
}
foo() // 'foo()' 可以正常呼叫
```
那我前面為什麼說這個阻擋又是不全面的,這個是書上沒有解釋的地方,我也找不到解釋或別的答案,導致我十分的困惑
阻擋不全面是因為報錯的原因是`TypeError`而不是`ReferenceError`, `TypeError`的原因我們可以看到,是因為foo的值是`undefined`
``` js
console.log(foo) // 'undefined'
foo() // TypeError: foo is not a function
```
這說明在全域性作用域中的那一刻是有這個變數的,只不過還沒被賦值為函式,這種狀態就好像是這樣(結合變數提升與函式提升的知識):
``` js
foo() // TypeError: foo is not a function
var foo = function () {
console.log('foo()')
}
```
如果塊作用域前呼叫的報錯是`ReferenceError`這就完完全全表示那一刻沒有`foo`這個變數
區別`TypeError`而不是`ReferenceError`
``` js
console.log(a) // `ReferenceError` 根本沒申明過這個變數
var b = 1
b() // `TypeError` 有這個變數名,但是使用型別上錯誤
```
## 寫在最後
不管怎樣,雖然對這個現象很困惑,但還是將它記錄下來說不定以後就懂了,但不管原因是怎樣的,別這麼寫就對了,何必難為自己,難為別人呢,對吧!
``` js
// 請一定不要這麼寫,除非他是你的仇人
{
function foo () {
console.log('foo()')
}
}
foo() // 'foo()'
// 還算正常關係
foo()
function foo () {
console.log('foo()')
}
// 跟他情深深
function foo () {
console.log('foo()')
}
f