Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 亚洲国产精品网站久久,91精品国产免费久久久久久,高清国产精品入口麻豆

          整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          JavaScript 函數(shù)執(zhí)行方式

          數(shù)的各種執(zhí)行方式

          ① 普通函數(shù)調(diào)用(包括匿名函數(shù)自調(diào)用)

          ② 構(gòu)造函數(shù)執(zhí)行 new 函數(shù)

          ③ 作為對象的成員方法執(zhí)行

          ④ 通過call和apply執(zhí)行

          call和apply可以明顯控制變量污染的風(fēng)險(xiǎn)。

          實(shí)例1:

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

          實(shí)例2:

          <script type="text/javascript">
          //call方式執(zhí)行函數(shù)
          function say(){
          document.write("在"+this.addr+'演講');
          }
          var dog = {addr:'德國',color:'black'};
          //dog對象去調(diào)用say()函數(shù)執(zhí)行
          //通過"call()"實(shí)現(xiàn)
          //函數(shù).call(函數(shù)內(nèi)部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(); //沒有結(jié)果
          </script>

          實(shí)例3:

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

          注意:call和apply的區(qū)別在于語法格式區(qū)別

          實(shí)例3:

          JavaScript在我們?nèi)粘i_發(fā)中扮演著至關(guān)重要的角色,大部分時(shí)間都與它打交道,因此對這門語言的了解再多也不為過。

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

          以 Google 瀏覽器為例,JavaScript 代碼由 V8 引擎負(fù)責(zé)解釋執(zhí)行。代碼的執(zhí)行總體上經(jīng)歷以下三個(gè)步驟:

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

          整個(gè)流程圖如下:

          生成AST

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

          答案肯定是不行,因?yàn)闉g覽器并不能理解我們所寫的代碼。這個(gè)理由就像將html需要解析為DOM一樣,瀏覽器并不能理解我們所編寫的代碼,需要將我們寫的代碼編譯成瀏覽器能夠理解的結(jié)構(gòu),也就是AST。

          AST是一種非常重要的數(shù)據(jù)結(jié)構(gòu),許多著名的項(xiàng)目都在使用它。

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

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

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

          一、詞法分析

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

          二、語法分析

          語法分析又稱解析,將上一步生成的token數(shù)據(jù)根據(jù)語法規(guī)則轉(zhuǎn)化為AST。在轉(zhuǎn)化過程中,如果不符合語法規(guī)則,會終止轉(zhuǎn)化并拋出一個(gè)語法錯(cuò)誤。轉(zhuǎn)化成的AST如下圖:

          可以通過 AST可視化網(wǎng)站:https://astexplorer.net/ 來體驗(yàn)成生成AST。

          除了生成AST,該階段還會創(chuàng)建代碼塊的執(zhí)行上下文。其實(shí)上述的編譯過程都發(fā)生在v8引擎內(nèi)部,對于我們開發(fā)者來說完全是黑盒的,但是執(zhí)行上下文這個(gè)概念卻是至關(guān)重要的,因?yàn)樗谴a運(yùn)行的基本環(huán)境。

          生成字節(jié)碼

          生成AST后,接著解釋器 Ignition 就會將AST轉(zhuǎn)化為字節(jié)碼并解釋執(zhí)行字節(jié)碼。

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

          其實(shí)一開始v8引擎并不會將AST轉(zhuǎn)化為字節(jié)碼,而是直接將AST轉(zhuǎn)化為機(jī)器碼并執(zhí)行。雖然執(zhí)行效率特別高,但是同時(shí)暴露出來了嚴(yán)重的內(nèi)存占用問題。因?yàn)関8引擎要消耗大量的內(nèi)存來存放轉(zhuǎn)化后的機(jī)器碼。為了解決內(nèi)存占用的問題,v8團(tuán)隊(duì)引入了字節(jié)碼,花了大量的時(shí)間,完成了當(dāng)前的這套架構(gòu)。

          解釋下字節(jié)碼是什么,字節(jié)碼是介于AST和機(jī)器碼之間的一種代碼,字節(jié)碼需要解釋器將其轉(zhuǎn)化為機(jī)器碼之后才能執(zhí)行。為了更好的去理解字節(jié)碼,下面是源碼、字節(jié)碼、機(jī)器碼的一個(gè)對比圖:

          可以看出,字節(jié)碼對比機(jī)器碼占用的空間要小得多。所以使用字節(jié)碼可以減少系統(tǒng)的內(nèi)存使用。

          執(zhí)行代碼

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

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

          總結(jié)

          至此本文分析完了 JavaScript 代碼執(zhí)行的整個(gè)階段。在宏觀角度上 JavaScript 代碼會經(jīng)歷如下步驟:

          1. 解析器將 JavaScript 代碼解析(詞法分析、語法分析)成AST并創(chuàng)建執(zhí)行上下文
          2. 解釋器 Ignition 將AST轉(zhuǎn)化為字節(jié)碼
          3. 解釋器 Ignition 對字節(jié)碼逐條解釋執(zhí)行
          4. 如果發(fā)現(xiàn)熱點(diǎn)代碼(HotSpot),后臺編譯器 TurboFan 會將熱點(diǎn)代碼編譯成機(jī)器碼并保存,進(jìn)而提升執(zhí)行效率。

          整個(gè)JavaScript代碼執(zhí)行是慢啟動,越執(zhí)行越快。這種字節(jié)碼配合解釋器和編譯器的技術(shù)叫做即時(shí)編譯(JIT)。v8引擎也是基于這種技術(shù)來實(shí)現(xiàn)對內(nèi)存占用和執(zhí)行效率的調(diào)控

          最后在JavaScript代碼執(zhí)行過程中,最重要的部分就是執(zhí)行上下文了,它是代碼運(yùn)行時(shí)的基本環(huán)境。

          參考鏈接

          • 瀏覽器工作原理與實(shí)踐: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/

          來源:微信公眾號:大轉(zhuǎn)轉(zhuǎn)FE

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

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

          1 <script>標(biāo)簽嵌入

          此種嵌入方法無法操作<script>之后的DOM元素。因?yàn)?lt;script>之后的DOM元素還未構(gòu)造,因此在<script>標(biāo)簽內(nèi)就無法取得位于其后的DOM元素。

          2 讀取外部JavaScript文件

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

          3 onload嵌入

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

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

          當(dāng)window.onload事件觸發(fā)時(shí),頁面上所有的DOM、樣式表、腳本、圖片、flash都已經(jīng)加載完成了。

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

          window.onload和body中onload也有些許區(qū)別:

          <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下,結(jié)果為 :

          "DOMContentLoaded"
          "bodyonload"

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

          在chrome下,結(jié)果為:

          DOMContentLoaded
          window.onload
          bodyonload

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

          chrome和IE10、FireFox的結(jié)果竟然是一樣的:

          DOMContentLoaded
          window.onload

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

          4 DOM ContentLoaded嵌入

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

          在chrome、IE10和FireFox中,執(zhí)行結(jié)果是:DOMContentLoaded然后才是onload的輸出。所以說一般情況下,DOMContentLoaded事件要在window.onload之前執(zhí)行,當(dāng)DOM樹構(gòu)建完成的時(shí)候就會執(zhí)行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>

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

          5 動態(tài)載入JavaScript文件

          5.1 使用原生js方法

          動態(tài)創(chuàng)建script標(biāo)簽,并指定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');
          });

          還可以使用同樣的原理動態(tài)加載css文件,只不過插入的的父節(jié)點(diǎn)是head標(biāo)簽。

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

          該種方式可以實(shí)現(xiàn)js文件的動態(tài)加載,原理就是在重寫文檔流,這種方式會導(dǎo)致整個(gè)頁面重繪。

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

          需要注意的是特殊字符的轉(zhuǎn)義。

          5.3 使用jQuery

          使用getScript(url,callback)方法實(shí)現(xiàn)動態(tài)加載js文件

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

          -End-


          主站蜘蛛池模板: 午夜福利一区二区三区高清视频| 91福利一区二区| 精品一区二区三区四区在线播放 | 国产韩国精品一区二区三区久久| 波多野结衣中文字幕一区二区三区 | 日本精品一区二区久久久| 无码中文字幕一区二区三区| 无码av免费一区二区三区| 日本中文字幕在线视频一区| 韩国资源视频一区二区三区| 无码一区二区三区爆白浆| 亚洲一区二区三区不卡在线播放| 亚洲AV美女一区二区三区| 国产精品一区二区久久不卡| 99精品久久精品一区二区| 精品aⅴ一区二区三区| 日本精品高清一区二区| 亚洲色精品vr一区二区三区| 久久综合一区二区无码| 久久久久女教师免费一区| av在线亚洲欧洲日产一区二区| 精品成人一区二区三区免费视频| 99偷拍视频精品一区二区| 国产精品无码亚洲一区二区三区| 国产精品美女一区二区三区| 丰满爆乳无码一区二区三区| 日本精品高清一区二区2021| 午夜视频在线观看一区二区| 国产天堂在线一区二区三区| 动漫精品一区二区三区3d| 日本精品一区二区三区在线视频| 一区二区三区高清在线| 亚洲综合无码AV一区二区 | 亚洲日本va一区二区三区| 日韩一区二区视频| 国产微拍精品一区二区| 亚洲国产精品一区二区第四页 | 日本精品夜色视频一区二区| 久久久久人妻一区精品果冻| 另类一区二区三区| 亚洲Av高清一区二区三区|