javascript
JS 作用域与变量提升---JS 学习笔记(三)
你知道下面的JavaScript代碼執行時會輸出什么嗎?
var foo = 1; function bar() {if (!foo) {var foo = 10;}console.log(foo); } bar();答案是“10”,吃驚嗎?那么下面的可能會真的讓你大吃一驚:
?
var a = 1; function b() {a = 10;return;function a() {} } b(); console.log(a);答案是 “1”。為什么會這樣呢,這就涉及到 JS 里面的作用域、作用域鏈和提升的相關知識了。
首先要明白 作用域和作用域鏈的內容(點擊閱讀),現在主要介紹提升。
?
在 JavaScript 中,當遇到 var a = 1; 這個語句時,我們可能會這么認為,“為一個變量分配內存,給這個變量命名為 a,再把 1 保存進去”。然而這個過程并不完全正確。當編譯器遇到 var a = 1 時,會做以下兩個步驟:
1. 遇到 var a ,首先會先看看當前的作用域中是否已經有 a,若有,就不再聲明 a,若沒有,就會在當前的作用域,創建一個 a
2. 然后處理 a = 1 。先查看當前作用域,是否有 a 。如果有,就把 1 賦值給 a 。如果沒有,就向上一個作用域中尋找 a,直到尋找到全局作用域。全局作用域中如果還沒有,就會拋出異常。
所以,當我們看到 var a = 1; 會認為這是一個聲明,實際上這是兩個聲明, var a 和 a = 1 。第一個聲明會在編譯階段進行,第二個聲明會在原地等待執行。函數聲明和變量聲明總會被 JavaScript 的編譯器提升到他們所在作用域的頂部。有了這些知識就可以解釋上面的代碼了
第一段代碼實際上如下圖:在遇到并執行 bar()函數時,執行到 if 語句里面的 foo,此時會先查詢 bar()函數的作用域內有沒有聲明 foo:
若沒有聲明,就像上一個作用域中尋找 foo 有沒有被聲明。
若聲明了,就直接將聲明提升到 bar 作用域里的頂部(foo = 10 留在原地按順序等待執行),這樣,foo 就是 undefined,!foo 就是 true,可以進入 if 循環。
第二段代碼實際上如下圖:執行 b()時,首先就是 a = 10;這條語句,執行這條語句之前,先看 a 在 b 中是否被聲明,若沒有被聲明就向上一個作用域中尋找 a ,現在的情況是,在 b 函數內部,a 以函數聲明的方式,被聲明了,那么就要把這個 a 函數聲明提升到 a 所在的作用域的頂部,再按順序執行后面的代碼。
?
?
?
對于提升總結的知識點:
1. 函數聲明和變量聲明都會提升,但在同一個作用域相同名字的函數聲明優先于變量聲明。
2. 變量聲明會提升,但變量賦值的過程不會提升,會在原地等待被執行。
3. 提升后,賦值語句會向前覆蓋提升的內容。例子 2 中,b 函數的內部,最開始 a 是函數提升,a 的本質是函數,但是函數提升后,執行了一個賦值語句:a = 10;此時,a 就是一個 number 類型的變量了。
?
對于這種情況,我們在寫 JavasScript 代碼的時候該怎么做呢?
使用單 var 模式:避免變量提升所帶來的問題
/*jslint onevar: true [...] */ function foo(a, b, c) {var x = 1,bar,baz = "something"; }?
本文參考以下資料:
顏海鏡的博客:JavaScript作用域鏈和提升機制
你不知道的JavaScript
JavaScript高階程序設計
?
轉載于:https://www.cnblogs.com/rougan/p/10606755.html
總結
以上是生活随笔為你收集整理的JS 作用域与变量提升---JS 学习笔记(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AI 基础
- 下一篇: java1.8之supplier