JavaScript | 思惟導圖 | 掌握變量提高的處理機制

公衆號:朝霞的光影筆記 ID:zhaoxiajingjing

公衆號:朝霞的光影筆記 ID:zhaoxiajingjing

0 / 變量提高處理機制

變量提高:在當前上下文中(全局/私有/塊級),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

1 / 練習題目

(1)var的變量提高
/*
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進制地址放到棧內存中與變量關聯起來

(2)function 的變量提高
/*
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();

△ 匿名函數具名化

把本來做爲值的函數表達式的匿名函數「具名化」:

① 這個名字不能在函數體外部訪問,也就是不會出如今當前上下文中

② 函數執行時,造成私有上下文,會把這個「具名化」的名字做爲該上下文中的私有變量(它的值就是這個函數體)來處理

③ 在函數體內部不能修改這個名字的值,除非是從新聲明這個變量

(3)不帶var的
/*
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的

(4)帶let的
/*
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的

(5)在全局上下文的映射

基於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 映射機制:一個修改另外一個也會修改

△ 全局上下文的映射機制

2 / 變量提高的題目

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();

△ 答案是?

公衆號:朝霞的光影筆記 ID:zhaoxiajingjing

△ 圖1.1_不論判斷條件是否成立:var都會變量提高;function的要複雜一些,後面再說~

- end -

公衆號:朝霞的光影筆記 ID:zhaoxiajingjing

相關文章
相關標籤/搜索