整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          JavaScript 函數執行方式

          數的各種執行方式

          ① 普通函數調用(包括匿名函數自調用)

          ② 構造函數執行 new 函數

          ③ 作為對象的成員方法執行

          ④ 通過call和apply執行

          call和apply可以明顯控制變量污染的風險。

          實例1:

          <script type="text/javascript">
          //call方式執行函數
          function say(){
          document.write("在"+this.addr+'演講');
          }
          var dog = {addr:'德國',color:'black'};
          //dog對象去調用say()函數執行
          //通過"call()"實現
          //函數.call(函數內部this的指引,形參1, 形參2, 形參3...);
          say.call(dog);//在德國演講
          var cat = {addr:'波斯灣'}
          say.call(cat);//在波斯灣演講
          //dog.express = say;
          //dog.express = "abc";//同名的express把同名的方法污染了
          //dog.express();
          </script>

          實例2:

          <script type="text/javascript">
          //call方式執行函數
          function say(){
          document.write("在"+this.addr+'演講');
          }
          var dog = {addr:'德國',color:'black'};
          //dog對象去調用say()函數執行
          //通過"call()"實現
          //函數.call(函數內部this的指引, 形參1, 形參2, 形參3...);
          say.call(dog);//在德國演講
          var cat = {addr:'波斯灣'}
          say.call(cat);//在波斯灣演講
          dog.express = say;
          dog.express(); //顯示:在德國演講
          dog.express = "abc";//同名的express把同名的方法污染了
          document.write(dog.express);//顯示:abc
          dog.express(); //沒有結果
          </script>

          實例3:

          <script type="text/javascript">
          //call方式執行函數
          function run(time,addr){
          document.write(this.name+"時間:"+time+",在"+addr+"跑步");
          }
          
          var tiger = {name:'東北虎',weight:220}
          run.call(tiger); //東北虎時間:undefined,在undefined跑步
          run.call(tiger,'早上','深山老林');//東北虎時間:早上,在深山老林跑步
          
          var cat = {name:'kitty'}
          run.apply(cat,['傍晚','屋后']);//kitty時間:傍晚,在屋后跑步
          </script>

          注意:call和apply的區別在于語法格式區別

          實例3:

          JavaScript在我們日常開發中扮演著至關重要的角色,大部分時間都與它打交道,因此對這門語言的了解再多也不為過。

          雖然有很多關于JavaScript的書籍和資料,但絕大多數都從JavaScript語言本身的角度去分析其語法和語義,很少有與JavaScript具體執行過程相關的分析資料。因此,我邀請大家一起從瀏覽器的角度來看一下一段JavaScript代碼到底是如何執行的。

          以 Google 瀏覽器為例,JavaScript 代碼由 V8 引擎負責解釋執行。代碼的執行總體上經歷以下三個步驟:

          1. 將代碼解析為抽象語法樹(AST)并創建執行上下文
          2. 根據 AST 生成字節碼作為中間代碼
          3. 解釋器 Ignition 會逐條解釋執行代碼

          整個流程圖如下:

          生成AST

          為什么要將代碼解析成AST呢,直接用原代碼不行嗎?

          答案肯定是不行,因為瀏覽器并不能理解我們所寫的代碼。這個理由就像將html需要解析為DOM一樣,瀏覽器并不能理解我們所編寫的代碼,需要將我們寫的代碼編譯成瀏覽器能夠理解的結構,也就是AST。

          AST是一種非常重要的數據結構,許多著名的項目都在使用它。

          比如Babel,Babel被用于代碼轉換,將es6的代碼轉換為es5的代碼,用于解決兼容性問題,Babel的工作原理就是將es6源碼解析為AST,再將es6的AST轉化為es5的AST,最后利用es5的AST生成源碼。

          類似的還有ESlint,ESlint是用來檢查js代碼規范的插件,它的檢查流程也是將源碼解析成AST,再利用AST來檢查代碼的規范問題。

          將源碼解析成AST通常需要兩個步驟:

          一、詞法分析

          詞法分析又稱為分詞(tokenize),是將一行行代碼拆分為一個個token。如下圖:

          二、語法分析

          語法分析又稱解析,將上一步生成的token數據根據語法規則轉化為AST。在轉化過程中,如果不符合語法規則,會終止轉化并拋出一個語法錯誤。轉化成的AST如下圖:

          可以通過 AST可視化網站:https://astexplorer.net/ 來體驗成生成AST。

          除了生成AST,該階段還會創建代碼塊的執行上下文。其實上述的編譯過程都發生在v8引擎內部,對于我們開發者來說完全是黑盒的,但是執行上下文這個概念卻是至關重要的,因為它是代碼運行的基本環境。

          生成字節碼

          生成AST后,接著解釋器 Ignition 就會將AST轉化為字節碼并解釋執行字節碼。

          為什么又要將AST解析成字節碼呢,上文不是說過瀏覽器可以理解AST嗎?答案是解決內存占用的問題。

          其實一開始v8引擎并不會將AST轉化為字節碼,而是直接將AST轉化為機器碼并執行。雖然執行效率特別高,但是同時暴露出來了嚴重的內存占用問題。因為v8引擎要消耗大量的內存來存放轉化后的機器碼。為了解決內存占用的問題,v8團隊引入了字節碼,花了大量的時間,完成了當前的這套架構。

          解釋下字節碼是什么,字節碼是介于AST和機器碼之間的一種代碼,字節碼需要解釋器將其轉化為機器碼之后才能執行。為了更好的去理解字節碼,下面是源碼、字節碼、機器碼的一個對比圖:

          可以看出,字節碼對比機器碼占用的空間要小得多。所以使用字節碼可以減少系統的內存使用。

          執行代碼

          對于一段第一次被執行的字節碼,解釋器 Ignition 會逐條解釋并執行。在執行的過程中,如果發現熱點代碼(Hotspot),比如說一段被重復執行多次的代碼,后臺的 編譯器 TurboFan 就會將該段熱點字節碼編譯成機器碼并保存起,當下次在執行到該段熱點代碼時,只需要執行編譯后的機器碼就行,這樣就節提升了大量的執行效率。執行流程如下圖所示:

          這種字節碼配合解釋器和編譯器的技術正是最近很火的技術————即時編譯(JIT)

          總結

          至此本文分析完了 JavaScript 代碼執行的整個階段。在宏觀角度上 JavaScript 代碼會經歷如下步驟:

          1. 解析器將 JavaScript 代碼解析(詞法分析、語法分析)成AST并創建執行上下文
          2. 解釋器 Ignition 將AST轉化為字節碼
          3. 解釋器 Ignition 對字節碼逐條解釋執行
          4. 如果發現熱點代碼(HotSpot),后臺編譯器 TurboFan 會將熱點代碼編譯成機器碼并保存,進而提升執行效率。

          整個JavaScript代碼執行是慢啟動,越執行越快。這種字節碼配合解釋器和編譯器的技術叫做即時編譯(JIT)。v8引擎也是基于這種技術來實現對內存占用和執行效率的調控

          最后在JavaScript代碼執行過程中,最重要的部分就是執行上下文了,它是代碼運行時的基本環境。

          參考鏈接

          • 瀏覽器工作原理與實踐:https://blog.poetries.top/browser-working-principle/guide/part2/lesson07.html#%E5%8F%98%E9%87%8F%E6%8F%90%E5%8D%87-hoisting
          • How JavaScript Works:https://www.freecodecamp.org/news/javascript-under-the-hood-v8/

          來源:微信公眾號:大轉轉FE

          出處:https://mp.weixin.qq.com/s/ZFtxVyERBkCgSadQqYxijQ

          了執行Javascript,需要在HTML文件內以特定的方式書寫JavaScript的代碼,JavaScript的書寫方法有多種,其執行的流程也各不相同:

          1 <script>標簽嵌入

          此種嵌入方法無法操作<script>之后的DOM元素。因為<script>之后的DOM元素還未構造,因此在<script>標簽內就無法取得位于其后的DOM元素。

          2 讀取外部JavaScript文件

          此種嵌入方法可以指定defer、async屬性。defer可以推遲執行,async可以異步執行。

          3 onload嵌入

          此種嵌入方法在頁面讀取完后再對其執行,所以可以對所有的DOM元素操作。

          <body onload="alert('hello')">
          window.onload = function(){alert('hello');};

          當window.onload事件觸發時,頁面上所有的DOM、樣式表、腳本、圖片、flash都已經加載完成了。

          //window.onload不能同時編寫多個。
          //以下代碼無法正確執行,結果只輸出第二個。
          window.onload = function(){
            alert("test1");
          };
          
          window.onload = function(){
            alert("test2");
          };
          
          //$(document).ready()能同時編寫多個
          //結果兩次都輸出
          $(document).ready(function(){ 
             alert("Hello World"); 
          }); 
          $(document).ready(function(){ 
             alert("Hello again"); 
          }); 

          window.onload和body中onload也有些許區別:

          <html xmlns="http://www.w3.org/1999/xhtml">
          <head>
              <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
              <title></title>
              <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.0.js"></script>
              <script language="javascript">
                  window.onload = haha;
                  function haha(){console.log("window.onload");}
          
                  if(document.addEventListener){
                      function DOMContentLoaded(){
                          console.log("DOMContentLoaded");
                      }
                      document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
                  }</script>
          </head>
          <body onload="console.log('bodyonload');">
                  <div id="div1">a</div>
          </body>
          </html>

          在IE10和FireFox下,結果為 :

          "DOMContentLoaded"
          "bodyonload"

          說明body中的onload會覆蓋window.onload

          在chrome下,結果為:

          DOMContentLoaded
          window.onload
          bodyonload

          然后,如果把javascript代碼移到最下面,結果又會是什么樣呢?

          chrome和IE10、FireFox的結果竟然是一樣的:

          DOMContentLoaded
          window.onload

          IE 10、Fire Fox可以理解,window.on load和body中的 on load 誰在下面就是誰覆蓋誰,只會執行后面的那個。

          4 DOM ContentLoaded嵌入

          onload方法可能需要等待時間,而本方法可以在完成HTML解析后發生的事件,減少等待時間。

          在chrome、IE10和FireFox中,執行結果是:DOMContentLoaded然后才是onload的輸出。所以說一般情況下,DOMContentLoaded事件要在window.onload之前執行,當DOM樹構建完成的時候就會執行DOMContentLoaded事件。

          <html xmlns="http://www.w3.org/1999/xhtml">
          <head>
              <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
              <title></title>
              <script type="text/javascript" src="jquery2.js"></script>
              <script language="javascript">
                  window.onload = haha;
                  function haha(){console.log(document.getElementById("div1"));}
                  if(document.addEventListener){
                      function DOMContentLoaded(){
                          console.log("DOMContentLoaded");
                      }
                      document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
                  }
              </script>
          </head>
          <body>
              <div id="div1">a</div>
          </body>
          </html>

          如果你是個jQuery使用者,你可能會經常使用$(document).ready();或者$(function(){}),這都是使用了DOMContentLoaded事件

          5 動態載入JavaScript文件

          5.1 使用原生js方法

          動態創建script標簽,并指定script的src屬性

          function loadJs(url, callback) {
              var script = document.createElement('script');
              script.type = "text/javascript";
              if (typeof(callback) != "undefined") {
                  if (script.readyState) {
                      script.onreadystatechange = function() {
                          if (script.readyState == "loaded" || script.readyState == "complete") {
                              script.onreadystatechange = null;
                              callback();
                          }
                      }
                  } else {
                      script.onload = function() {
                          callback();
                      }
                  }
              }
              script.src = url;
              document.body.appendChild(script);
          }
          loadJs("test.js", function() {
              alert('done');
          });

          還可以使用同樣的原理動態加載css文件,只不過插入的的父節點是head標簽。

          5.2 使用document.write/writeln()方式

          該種方式可以實現js文件的動態加載,原理就是在重寫文檔流,這種方式會導致整個頁面重繪。

          document.writeln("<script src=\"http://lib.sinaapp.com/js/jquery/1.6/jquery.min.js\"></script>");

          需要注意的是特殊字符的轉義。

          5.3 使用jQuery

          使用getScript(url,callback)方法實現動態加載js文件

          $.getScript('test.js',function(){
              alert('done');
          });

          -End-


          主站蜘蛛池模板: 国产对白精品刺激一区二区| 人妻少妇精品视频一区二区三区| 亚洲熟妇av一区| 日本一区高清视频| 无码人妻精品一区二区三区66| 国产色欲AV一区二区三区| 无码人妻少妇色欲AV一区二区| 日本无码一区二区三区白峰美| 日韩人妻一区二区三区蜜桃视频| 国产色欲AV一区二区三区| 一区二区三区高清| av一区二区三区人妻少妇| 日韩欧美一区二区三区免费观看| 成人区精品一区二区不卡亚洲| 无码中文字幕一区二区三区| 综合无码一区二区三区四区五区| 亚洲午夜精品一区二区麻豆| 亚洲一区二区三区在线观看网站| 亚洲av无码一区二区三区四区| 亚洲国产精品无码第一区二区三区| 成人一区专区在线观看 | 日本一区精品久久久久影院| 免费观看一区二区三区| 国产一区二区三区久久| 综合无码一区二区三区四区五区| 国产精品av一区二区三区不卡蜜| 精品国产免费观看一区| 国产精品第一区第27页| 久久国产精品一区二区| 一区二区三区视频| 中文字幕一区在线| 人妻av综合天堂一区| 少妇人妻偷人精品一区二区| 国产精品一区视频| 国产福利电影一区二区三区,亚洲国模精品一区 | 理论亚洲区美一区二区三区 | 国产在线视频一区二区三区| 制服丝袜一区二区三区| 97一区二区三区四区久久| V一区无码内射国产| 一区二区传媒有限公司|