當瀏覽器開闢出供代碼執行的棧內存後,代碼並無自上而下當即執行,而是繼續作了一些事情:把當前做用域中全部帶var/function關鍵字的進行提早的聲明和定義 =>變量提高機制javascript
- 帶var的只是提早聲明(declare) 「var a;」 若是隻聲明沒有賦值,默認值是undefined
- 帶function的不只聲明,並且還定義了(defined) 「a=13」定義其實就是賦值,準確來講就是讓變量和某個值進行關聯
1.帶var和不帶var的區別java
//=>在全局做用域下的區別
/* * 不帶var的:至關於給全局對象window設置了一個屬性a * window.a = 13; */
a = 13;
console.log(a); //=>window.a
/* * 棧內存變量存儲空間 * b * 帶var的:是在全局做用域下聲明瞭一個變量b(全局變量),可是在全局下聲明的變量也一樣至關於給window增長了一個對應的屬性(只有全局做用域具有這個特色) */
var b = 14; //=>建立變量b & 給window設置了屬性b
console.log(b); //=>14
console.log(window.b); //=>14
複製代碼
建立函數es6
函數執行web
關於堆棧內存釋放問題(以谷歌webkit內核爲例子)瀏覽器
函數執行就會造成棧內存(從內存中分配的一塊空間),若是內存都不銷燬釋放,很容易就會致使棧內存溢出(內存爆滿,電腦就卡死了),堆棧內存的釋放問題是學習JS的核心知識之一閉包
//=>建立一個引用類型值,就會產生一個堆內存
//若是當前建立的堆內存不被其它東西所佔用了(瀏覽器會在空閒的時候,查找每個內存的引用情況,不被佔用的都會給回收釋放掉),則會釋放
let obj = {
name : 'zhufeng'
};
let oop = obj;
//此時obj和oop都佔用着對象的堆內存,想要釋放堆內存,須要手動解除變量和值的關聯(null:空對象指針)
obj = null;
oop = null;
複製代碼
棧內存釋放函數
//=>打開瀏覽器造成的全局做用域是棧內存
//=>手動執行函數造成的私有做用域是棧內存
//=>基於ES6中的let/const造成的塊做用域也是棧內存
//=>....
/* * 全局棧內存:關掉頁面的時候纔會銷燬 * 私有棧內存: * 1.通常狀況下,函數只要執行完成,造成的私有棧內存就會被銷燬釋放掉(排除出現無限極遞歸、出現死循環的模式) * 2.可是一旦棧內存中的某個東西(通常都是堆地址)被私有做用域之外的事物給佔用了,則當前私有棧內存不能當即被釋放銷燬(特色:私有做用域中的私有變量等信息也保留下來了) =>市面上認爲的閉包:函數執行造成不能被釋放的私有棧內存,這樣的纔是閉包 */
function fn(){
//...
}
fn(); //=>函數執行造成棧內存,執行完成棧內存銷燬
function X(){
return function(){
//...
}
}
let f=X(); //=>f佔用了X執行造成的棧內存中的一個東西(返回小函數對應的堆),則X執行造成的棧內存不能被釋放了
複製代碼
1.let和const不存在變量提高機制
oop
建立變量的六種方式中:var/function有變量提高,而let/const/class/import都不存在這個機制學習
2.var容許重複聲明,而let是不容許的
ui
在相同的做用域中(或執行上下文中)
- 若是使用var/function關鍵詞聲明變量而且重複聲明,是不會有影響的(聲明第一次以後,以後再遇到就再也不重複聲明瞭)
- 可是使用let/const就不行,瀏覽器會校驗當前做用域中是否已經存在這個變量了,若是已經存在了,則再次基於let等從新聲明就會報錯
//=>在瀏覽器開闢棧內存供代碼自上而下執行以前,不只有變量提高的操做,還有不少其它的操做=>「詞法解析」或者「詞法檢測」:就是檢測當前即將要執行的代碼是否會出現「語法錯誤 SyntaxError」,若是出現錯誤,代碼將不會再執行(第一行都不會執行)
console.log(1); //=>這行代碼就已經不會再被執行了
let a = 12;
console.log(a);
let a = 13; //=>Uncaught SyntaxError: Identifier 'a' has already been declared
console.log(a);
複製代碼
//=>所謂重複是:無論以前經過什麼辦法,只要當前棧內存中存在了這個變量,咱們使用let/const等重複再聲明這個變量就是語法錯誤
console.log(a);
var a = 12;
let a = 13; //=>Uncaught SyntaxError: Identifier 'a' has already been declared
console.log(a);
複製代碼
3.let能解決typeof檢測時出現的暫時性死區問題(LET比VAR更嚴謹)
// console.log(a);
//=>Uncaught ReferenceError: a is not defined
// console.log(typeof a);
//=>"undefined" 這是瀏覽器BUG,本應該報錯由於沒有a(暫時性死區)
console.log(typeof a);
//=>Uncaught ReferenceError: Cannot access 'a' before initialization
let a;
複製代碼