亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

深入理解JavaScript中的預解析

2019-11-19 18:09:01
字體:
來源:轉載
供稿:網友

前言

JavaScript是解釋型語言是毋庸置疑的,但它是不是僅在運行時自上往下一句一句地解析的呢?

事實上或某種現象證明并不是這樣的,通過《JavaScript權威指南》及網上相關資料了解到,JavaScript有“預解析”行為。理解這一特性是很重要的,不然在實際開發中你可能會遇到很多無從解析的問題,甚至導致程序bug的存在。為了解析這一現象,也作為自己的一次學習總結,本文逐步引導你來認識JavaScript“預解析”,如果我的見解有誤,還望指正。

在ES6之前,變量使用var聲明,會存在變量的預解析(函數也有預解析),我相信很多同學在剛開始學JavaScript的時候被預解析搞得團團轉,雖然在ES6的時候引入let和const,但是現階段ES6并沒有完全普及,而且很多比較老的代碼都還是按照ES5的標準甚至是ES3的標準來書寫的。

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

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代碼執行的環境,稱之為全局作用域。

基本數據類型按照值來操作,引用數據類型按照地址來操作。

根據以上原則,以上的代碼在內存中的模型為:


內存模型.png

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

在以上的代碼的基礎上再執行:

console.log(func);console.log(func());

第一行輸出的是整個函數的定義部分(函數本身):


第一行代碼輸出結果.png

上面已經說明了,func存儲的是一個地址,該地址指向一塊堆內存,該堆內存就保留了函數的定義。

第二行輸出的是func函數的返回結果:


第二行代碼輸出結果.png

由于func函數沒有返回值,所以輸出undefined。

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

二、預解析

有了以上的內存模型的理解之后,就能更好的了解預解析的機制了。所謂的預解析就是:在當前作用域中,JavaScript代碼執行之前,瀏覽器首先會默認的把所有帶var和function聲明的變量進行提前的聲明或者定義。

2.1. 聲明和定義

var num = 24;

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

  1. 聲明:var num; 告訴瀏覽器在全局作用域中有一個num變量了,如果一個變量只是聲明了,但是沒有賦值,默認值是undefined。
  2. 定義: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);}

輸出結果.png

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

由于函數的聲明和定義是同時進行的,所以func()雖然是在func函數定義聲明處之前調用的,但是依然可以正常的調用,會正常輸出300。


內存模型.png

三、 作用域鏈

先理解以下三個概念:

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

以上代碼執行的時候,第一次輸出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);

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

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

在全局作用域中聲明變量帶var可以進行預解析,所以在賦值的前面執行不會報錯;聲明變量的時候不帶var的時候,不能進行預解析,所以在賦值的前面執行會報錯。

console.log(num1);var num1 = 12;console.log(num2);num2 = 12;

輸出結果.png

      num2 = 12; 相當于給window增加了一個num2的屬性名,屬性值是12;

      var num1 = 12; 相當于給全局作用域增加了一個全局變量num1,但是不僅如此,它也相當于給window增加了一個屬性名num,屬性值是12;

問題:在私有作用域中出現一個變量,不是私有的,則往上級作用域進行查找,上級沒有則繼續向上查找,一直找到window為止,如果window也沒有呢?

      獲取值:console.log(total); --> 報錯 Uncaught ReferenceError: total is not defined

      設置值:total= 100; --> 相當于給window增加了一個屬性名total,屬性值是100

function fn() { // console.log(total); // Uncaught ReferenceError: total is not defined total = 100;}fn();console.log(total);

注意:JS中,如果在不進行任何特殊處理的情況下,上面的代碼報錯,下面的代碼都不再執行了

五、 預解析中的一些變態機制

5.1 不管條件是否成立,都要把帶var的進行提前的聲明

if (!('num' in window)) {  var num = 12;}console.log(num); // undefined

JavaScript進行預解析的時候,會忽略所有if條件,因為在ES6之前并沒有塊級作用域的概念。本例中會先將num預解析,而預解析會將該變量添加到window中,作為window的一個屬性。那么 'num' in window 就返回true,取反之后為false,這時代碼執行不會進入if塊里面,num也就沒有被賦值,最后console.log(num)輸出為undefined。

5.2 只預解析“=”左邊的,右邊的是指,不參與預解析

fn(); // -> undefined(); // Uncaught TypeError: fn is not a functionvar fn = function () { console.log('ok');}fn(); -> 'ok'function fn() { console.log('ok');}fn(); -> 'ok'

建議:聲明變量的時候盡量使用var fn = ...的方式。

5.3 自執行函數:定義和執行一起完成

(function (num) { console.log(num);})(100);

自治性函數定義的那個function在全局作用域下不進行預解析,當代碼執行到這個位置的時候,定義和執行一起完成了。

補充:其他定義自執行函數的方式

~ function (num) {}(100) + function (num) {}(100) - function (num) {}(100) ! function (num) {}(100)

5.4 return下的代碼依然會進行預解析

function fn() {         console.log(num); // -> undefined return function () {     };         var num = 100;     }         fn();

函數體中return下面的代碼,雖然不再執行了,但是需要進行預解析,return中的代碼,都是我們的返回值,所以不進行預解析。

5.5 名字已經聲明過了,不需要重新的聲明,但是需要重新的賦值

var fn = 13;          function fn() {          console.log('ok');        }             fn(); // Uncaught TypeError: fn is not a function

經典題目

fn(); // -> 2            function fn() {console.log(1);}       fn(); // -> 2            var fn = 10; // -> fn = 10        fn(); // -> 10() Uncaught TypeError: fn is not a function       function fn() {console.log(2);}       fn();

總結

以上就是關于JavaScript中預解析的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩av影片在线观看| 日本久久亚洲电影| 亚洲欧美日韩爽爽影院| 国产成人一区二| 日韩在线一区二区三区免费视频| 国产精品一区专区欧美日韩| 日韩av在线不卡| 热久久99这里有精品| 国产精品6699| 亚洲影视中文字幕| 欧美色视频日本版| 欧美黄色片在线观看| 欧美影院在线播放| 成人久久一区二区| 久久久久久久久91| 97视频在线看| 韩日欧美一区二区| 日本精品一区二区三区在线播放视频| 国产精品无码专区在线观看| 欧美激情videoshd| 成人免费在线视频网址| 97视频人免费观看| 97色伦亚洲国产| xxxx性欧美| 国产欧美一区二区三区久久人妖| 亚洲欧美日韩精品久久亚洲区| 久久99国产综合精品女同| 欧美午夜精品久久久久久人妖| 成人a在线观看| 欧美成人精品激情在线观看| 欧美大学生性色视频| 日韩一级黄色av| 亚洲伦理中文字幕| 青青草精品毛片| 国产成人在线视频| 清纯唯美亚洲激情| 国产精品久久久久久久久男| 欧美在线激情视频| 成人h猎奇视频网站| 日韩激情片免费| 欧美成人精品在线| 午夜伦理精品一区| 欧美精品激情在线| 久久久久久尹人网香蕉| 草民午夜欧美限制a级福利片| 亚洲成人教育av| 久久视频免费在线播放| 欧美视频在线免费看| 国产一区二区精品丝袜| 日韩一区二区精品视频| 久久夜色精品国产亚洲aⅴ| 26uuu亚洲伊人春色| 欧美激情久久久久| 国产亚洲视频在线观看| 亚洲网站在线看| 日韩精品中文字| 欧美电影免费在线观看| 亚洲第一网站免费视频| 国产精品久久久久久久久粉嫩av| 日韩在线观看av| 久久免费视频网站| 亚洲精品大尺度| 成人a免费视频| 日韩电影中文字幕在线观看| 国产一区二区三区四区福利| 欧美日韩另类字幕中文| 91精品视频观看| 欧洲日本亚洲国产区| 91久久久在线| 日韩经典中文字幕在线观看| 久久久久久国产免费| 成人xxxx视频| 欧美日韩美女视频| 都市激情亚洲色图| 日韩福利伦理影院免费| 日韩精品福利在线| 欧美久久精品午夜青青大伊人| 欧美性猛交xxxx黑人猛交| 欧美在线视频免费观看| 国内揄拍国内精品少妇国语| 91av在线播放| 亚洲国产精品一区二区久| 亚洲国产欧美自拍| 91精品在线观看视频| 欧美国产日韩一区二区在线观看| 久久久久一本一区二区青青蜜月| 不用播放器成人网| 日韩视频免费观看| 久久久综合免费视频| 色与欲影视天天看综合网| 欧美视频一区二区三区…| 亚洲精品久久久久久久久久久久| 成人欧美一区二区三区黑人孕妇| 欧美日韩一区二区三区在线免费观看| 久久精品视频va| 国内精品久久久久伊人av| 亚洲男人第一av网站| 国产精品久久久久久超碰| 欧美激情久久久久久| 日本在线精品视频| 国产精品久久国产精品99gif| 亚洲一区二区久久久久久| www.亚洲一二| 98精品国产自产在线观看| 国产成人精品在线视频| 日韩av在线一区二区| 麻豆乱码国产一区二区三区| 98精品国产高清在线xxxx天堂| 亚洲精品白浆高清久久久久久| 欧美视频国产精品| 国产精品一区久久久| 亚洲免费视频一区二区| 日韩精品在线免费观看| 亚洲色图15p| 欧美日韩国产精品一区| 国产成人精品一区二区三区| 国产91亚洲精品| 91av网站在线播放| 成人黄色免费在线观看| 亚洲欧美国产视频| 欧美成人激情视频| 国产精品ⅴa在线观看h| 欧美成人免费小视频| 国产精品爱久久久久久久| 欧美另类69精品久久久久9999| 久久久女人电视剧免费播放下载| 欧美一性一乱一交一视频| 精品国产自在精品国产浪潮| 国产不卡av在线免费观看| 国产欧美一区二区三区视频| 亚洲国语精品自产拍在线观看| 97欧美精品一区二区三区| 高清在线视频日韩欧美| 成人国产精品av| 久久久中精品2020中文| 国产精品高清网站| 91在线网站视频| 日韩精品免费视频| 精品久久久久久亚洲精品| 欧美日本精品在线| 欧美日韩激情美女| 国产精品看片资源| 日韩在线视频二区| 国产精品白嫩初高中害羞小美女| 欧美黑人性生活视频| 久久精品国亚洲| 国产精品免费久久久久影院| 久久久久在线观看| 久久久精品网站| 青草青草久热精品视频在线网站| 久久精品精品电影网| 午夜欧美不卡精品aaaaa| 亚洲精品国偷自产在线99热| 日韩资源在线观看| 国产精品精品久久久| 国产成人在线亚洲欧美| 91情侣偷在线精品国产| 久久综合久久美利坚合众国| 日本久久久久久久| 97精品国产97久久久久久免费| 4p变态网欧美系列| 久久久久国产精品免费| 久久久天堂国产精品女人| www日韩欧美|