JavaScript的預解析

一、變量和函數在內存中的展示

JavaScript中的變量類型和其他語言一樣,有基本數據類型和引用數據類型。基本數據類型包括:undefined、null、boolean、String、Number;引用數據類型主要是對象(包括{}、[]、//、Date、Function等)。

var num = 24;
var obj = {name:'iceman' , age:24};
function func() {
 console.log('hello world');
}

當瀏覽器加載html頁面的時候,首先會提供一個供全局JavaScript代碼執行的環境,稱之爲全局作用域。
基本數據類型按照值來操作,引用數據類型按照地址來操作。
根據以上原則,以上的代碼在內存中的模型爲:

這裏寫圖片描述

基本類型是直接存儲在棧內存中,而對象是存儲在堆內存中,變量只是持有該對象的地址。所以obj持有一個對象的地址oxff44,函數func持有一個地址oxff66。

注意:函數的返回結果,return後面寫的是什麼,返回值就是什麼,如果沒有return,默認返回值是undefined。

二、預解析

所謂的預解析就是:在當前作用域中,JavaScript代碼執行之前,瀏覽器首先會默認的把所有帶var和function聲明的變量進行提前的聲明或者定義。

2.1. 聲明和定義

var num = 24;

這行簡單的代碼其實是兩個步驟:聲明和定義。

聲明:var num; 告訴瀏覽器在全局作用域中有一個num變量了,如果一個變量只是聲明瞭,但是沒有賦值,默認值是undefined。
定義:num = 12; 定義就是給變量進行賦值。

2.2. var聲明的變量和function聲明的函數在預解析的區別

var聲明的變量和function聲明的函數在預解析的時候有區別,var聲明的變量在預解析的時候只是提前的聲明,function聲明的函數在預解析的時候會提前聲明並且會同時定義。也就是說var聲明的變量和function聲明的函數的區別是在聲明的同時有沒同時進行定義。

2.3. 預解析只發生在當前的作用域下

程序最開始的時候,只對window下的變量和函數進行預解析,只有函數執行的時候纔會對函數中的變量很函數進行預解析。

console.log(num);
var num = 24;
console.log(num);

func(100 , 200); 
function func(num1 , num2) {
 var total = num1 + num2;
 console.log(total);
}

輸出結果:undefined
24
300

第一次輸出num的時候,由於預解析的原因,只聲明瞭還沒有定義,所以會輸出undefined;第二次輸出num的時候,已經定義了,所以輸出24。

這裏寫圖片描述

三、 作用域鏈

先理解以下三個概念:
1.函數裏面的作用域成爲私有作用域,window所在的作用域稱爲全局作用域;
2.在全局作用域下聲明的變量是全局變量;
3.在“私有作用域中聲明的變量”和“函數的形參”都是私有變量.

在私有作用域中,代碼執行的時候,遇到了一個變量,首先需要確定它是否爲私有變量,如果是私有變量,那麼和外面的任何東西都沒有關係,如果不是私有的,則往當前作用域的上級作用域進行查找,如果上級作用域也沒有則繼續查找,一直查找到window爲止,這就是作用域鏈。

當函數執行的時候,首先會形成一個新的私有作用域,然後按照如下的步驟執行:
1.如果有形參,先給形參賦值;
2.進行私有作用域中的預解析;
3.私有作用域中的代碼從上到下執行.

函數形成一個新的私有的作用域,保護了裏面的私有變量不受外界的干擾(外面修改不了私有的,私有的也修改不了外面的),這也就是閉包的概念。

console.log(total); 
var total = 0;
function func(num1, num2) {
 console.log(total); 
 var total = num1 + num2;
 console.log(total);
}
func(100 , 200);
console.log(total);

輸出結果:undefined
undefined
300
0

解釋:
以上代碼執行的時候,第一次輸出total的時候會輸出undefined(因爲預解析),當執行func(100,200)的時候,會執行函數體裏的內容,此時func函數會形成一個新的私有作用域,按照之前描述的步驟:
1.先給形參num1、num2賦值,分別爲100、200;
2.func中的代碼進行預解析;
3.執行func中的代碼。

因爲在func函數內進行了預解析,所以func函數裏面的total變量會被預解析,在函數內第一次輸出total的時候,會輸出undefined,接着爲total賦值了,第二次輸出total的時候就輸出300。 因爲函數體內有var聲明的變量total,函數體內的輸出total並不是全局作用域中的total。

最後一次輸出total的時候,輸出0,這裏輸出的是全局作用域中的total。

舉一反三:

console.log(total); 
var total = 0;
function func(num1, num2) {
 console.log(total); 
 total = num1 + num2;
 console.log(total);
}
func(100 , 200);
console.log(total);

結果:
undefined
0
300
300

將代碼作小小的變形之後,func函數體內的total並沒有使用var聲明,所以total不是私有的,會到全局作用域中尋找total,也就說說這裏出現的所有total其實都是全局作用域下的。

四、 全局作用域下帶var和不帶var的區別

在全局作用域中聲明變量帶var可以進行預解析,所以在賦值的前面執行不會報錯;聲明變量的時候不帶var的時候,不能進行預解析,所以在賦值的前面執行會報錯。
console.log(num1);   //undefined
var num1 = 12;   

 //什麼也不打印
console.log(num2);    //ReferenceError: num3 is not defined
num2 = 12;

console.log(num3);   //不執行(因爲上面的代碼報錯,下面的代碼都不再                執行了)

http://www.jb51.net/article/102018.htm
http://www.jianshu.com/p/c3276ff58c93

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章