變量提高:在當前上下文中(全局/私有/塊級),JS代碼自上而下執行以前,瀏覽器會處理一些事情(能夠理解爲詞法解析的一個環節,詞法解析必定是發生在代碼執行以前的):javascript
會把當前上下文中全部帶var/function
關鍵字的進行提早聲明或者定義java
var a = 10;
瀏覽器
① 聲明 declare:var a;
函數
② 定義 defined:a = 10;
spa
帶VAR的只提早聲明3d
帶FUNCTION的會提早聲明+定義 code
函數名就是變量名,函數是對象數據類型的須要堆內存存儲對象
如今代碼基本都用ES6語法的let/const寫了,因此var的變量提高會少不少。聲明函數也儘可能使用函數表達式來寫,這樣能夠規避掉直接使用function聲明函數的而產生的變量提高blog
/* EC(G) 全局執行上下文 VO(G) 變量對象 var a; 默認值是undefined ----- 代碼執行: */ console.log(a); //=> undefined var a = 12; //=> 建立12,a=12 賦值(聲明在變量提高階段完成了,瀏覽器懶得不會作重複的事情) a = 11; //=> 全局變量 a = 11; console.log(a); //=> 11
△ 變量提高ip
數據類型:
① 基本數據類型(string/number/boolean/null/undefined/symbol/bigin)
② 對象數據類型(object/functioin)
① 基本數據類型值:直接存儲在棧內存中
② 對象數據類型值:因爲數據類型比較複雜,存儲在堆內存中,把堆內存的16進制地址放到棧內存中與變量關聯起來
/* EC(G) 全局執行上下文 VO(G) 變量對象 fn = 0x000001堆內存地址[聲明+定義] ----- 代碼執行: */ fn(); //=> 函數執行的結果:輸出"hello" function fn(){ var a = 12; console.log('hello'); }
△ 函數
項目開發中推薦:函數表達式 var fn = function (){};
這樣,在變量提高階段只會聲明變量,不會賦值
fn(); //=> Uncaught TypeError: fn is not a function // 報錯後面的代碼就不執行了 var fn = function (){ // 函數表達式:在變量提高階段只會聲明fn,不會賦值了 console.log('hello'); }; fn();
△ 函數表達式
var fn = function AA(){ console.log('hello'); }; AA(); //=> Uncaught ReferenceError: AA is not defined
△ 匿名函數具名化
var fn = function AA(){ console.log('hello'); console.log(AA); //=> 輸出當前函數體 }; fn();
△ 匿名函數具名化
把本來做爲值的函數表達式的匿名函數「具名化」:
① 這個名字不能在函數體外部訪問,也就是不會出如今當前上下文中
② 函數執行時,造成私有上下文,會把這個「具名化」的名字做爲該上下文中的私有變量(它的值就是這個函數體)來處理
③ 在函數體內部不能修改這個名字的值,除非是從新聲明這個變量
/* EC(G) 全局執行上下文 VO(G) 變量對象 ----- 代碼執行: */ console.log('ok'); //=> 'ok' //=> 沒有寫VAR/FUNCTION的,不能在定義前使用 console.log(a); //=> Uncaught ReferenceError: a is not defined a=12; console.log(a);
△ 不帶var的
/* EC(G) 全局執行上下文 VO(G) 變量對象 ----- 代碼執行: */ console.log('ok'); //=> 'ok' //=>LET/CONST 沒有變量提高 console.log(a); //=> Uncaught ReferenceError: a is not defined let a = 12; a = 13; console.log(a);
△ 帶LET的
基於VAR/FUNCTION在 <u>全局上下文EC(G)</u> 中聲明的變量(全局變量)會「<u>映射</u>」到 <u>GO(window 全局對象)</u> 上一份,做爲它的屬性;並且一個修改另一個也會跟着修改
var a = 12; console.log(a); //=> 12 全局變量 console.log(window.a); //=> 12 映射到GO上的屬性 window.a = 11; console.log(a); //=> 11 映射機制:一個修改另外一個也會修改
△ 全局上下文的映射機制
fn(); function fn(){ console.log(1); } fn(); function fn(){ console.log(2); } fn(); var fn = function(){ console.log(3); } fn(); function fn(){ console.log(4); } fn(); function fn(){ console.log(5); } fn();
△ 答案是?
/** * EC(G)全局執行上下文 * VO(G) 變量對象 * fn = 0x0000001=>log1 * = 0x0000002=>log2 * = 0x0000003=>log4 * = 0x0000004=>log5 * 【var fn; 變量已經聲明過了,不會再重複執行了】 * -------- * 代碼執行: */ fn(); //=>5 function fn(){ console.log(1); } //=>再也不處理,變量提高階段搞過了 fn(); //=>5 function fn(){ console.log(2); } fn(); //=>5 var fn = function(){ console.log(3); } //=>var fn不用在處理了,可是賦值在變量提高階段沒處理過,此處須要處理 fn=window.fn=>3 fn(); //=>3 function fn(){ console.log(4); } fn(); //=>3 function fn(){ console.log(5); } fn(); //=>3
△ 變量提高
var foo = 1; function bar() { if (!foo) { var foo = 10; } console.log(foo); } bar();
△ 答案是?
△ 圖1.1_不論判斷條件是否成立:var都會變量提高;function的要複雜一些,後面再說~
- end -