在咱們的平常工做中,變量無處不在。更加深刻的去了解它,可以使得本身的JS水平更上一層樓, 從變量提高這個小知識點着手,讓咱們一塊兒來深刻了解JS吧!
html
console.log(a) // undefined
var a = 'hello JS'
/* 在咱們聲明a以前爲何輸出a不會報錯呢? 不急,讓咱們接着往下看 */
num = 6;
num++;
var num;
console.log(num) // 7 好奇怪,爲何給一個尚未聲明的變量賦值會不報錯呢
function hoistFunction() {
foo();
function foo() {
console.log('running...')
}
}
hoistFunction(); // running...
/* 最後一個栗子 */
alert(a) // function a { alert(10) }
a(); // 10
var a = 3;
function a() {
alert(10)
};
alert(a) // 3
a = 6;
a(); // throw error複製代碼
JS引擎會在正式執行代碼以前進行一次」預編譯「,預編譯簡單理解就是在內存中開闢一些空間,存放一些變量和函數。具體步驟以下(browser):segmentfault
GO/window = {
//頁面加載建立GO同時,建立了document、navigator、screen等等屬性,此處省略
a: undefined,
c: undefined,
b: function(y){
var x = 1;
console.log('so easy');
}
}複製代碼
GO/window = {
//變量隨着執行流獲得初始化
a: 1,
c: function(){
//...
},
b: function(y){
var x = 1;
console.log('so easy');
}
}
複製代碼
預解析機制使得變量提高(Hoisting),從字面上理解就是變量和函數的聲明會移動到移動到函數或者全局代碼的開頭位置。咱們再來分析一下小栗子加深一下理解。bash
console.log(a) // 執行以前,變量提高做爲window的屬性, 值被設置爲undefined
var a = 'hello JS'
/* JavaScript 僅提高聲明,而不提高初始化 */
num = 6;
num++;
var num;
console.log(num) // 變量提高 值爲undefined的num賦值爲6,再自增 => 7
function hoistFunction() {
foo();
function foo() {
console.log('running...')
}
}
hoistFunction(); // 函數聲明提高,能夠在函數體以前執行
/* 最後一個栗子 */
alert(a) // 最後的聲明爲函數聲明, 所以a此時爲函數體
a(); // 執行 a 函數,輸出10
var a = 3; // 3 賦給a
function a() {
alert(10)
};
alert(a) // 3
a = 6; // 6賦給a,不是一個函數,故下方執行throw error
a(); // throw error
複製代碼
注: JS並不存在真正的預編譯,var與function的提高實際是在語法分析階段就處理好的。並且JS的預編譯是以一個腳本文件爲塊的。一個腳本文件進行一次預編譯,而不是全文編譯完成再進行」預編譯」的。函數
理解了變量提高和函數提高能夠使得咱們在JS上走的更遠,可是咱們在開發中,不該該使用這一特性,而是要規範咱們的代碼,作到可維護性和可讀性。不管是變量仍是函數,都必須先聲明後使用。PS:在開發中應該使用let來約束變量提高。
spa
參考資料: code
https://developer.mozilla.org/zh-CN/docs/Glossary/Hoisting https://www.cnblogs.com/liuhe688/p/5891273.html http://dmitrysoshnikov.com/notes/note-4-two-words-about-hoisting/ https://segmentfault.com/a/1190000010187653htm