溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

js潛在規(guī)則有哪些

發(fā)布時間:2023-02-22 16:40:33 來源:億速云 閱讀:95 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“js潛在規(guī)則有哪些”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“js潛在規(guī)則有哪些”吧!


      宏任務(wù)和微任務(wù)

      采納 JSC 引擎的術(shù)語,我們把宿主發(fā)起的任務(wù)稱為宏觀任務(wù),把 JavaScript 引擎發(fā)起的任務(wù)稱為微觀任務(wù)。

      JavaScript 引擎等待宿主環(huán)境分配宏觀任務(wù),在操作系統(tǒng)中,通常等待的行為都是一個事件循環(huán),所以在 Node 術(shù)語中,也會把這個部分稱為事件循環(huán)。在底層的 C/C++ 代碼中,這個事件循環(huán)是一個跑在獨立線程中的循環(huán)。

      宏觀任務(wù)的隊列就相當(dāng)于事件循環(huán)。

      在宏觀任務(wù)中,JavaScript 的 Promise 還會產(chǎn)生異步代碼,JavaScript 必須保證這些異步代碼在一個宏觀任務(wù)中完成,因此,每個宏觀任務(wù)中又包含了一個微觀任務(wù)隊列。

      語句的執(zhí)行過程 (Completion Record )

      我們知道有的語句按順序執(zhí)行,有的語句會阻斷執(zhí)行。那么這是何種原因?qū)е碌哪兀?/p>

      我們來看一下js語句執(zhí)行的完成狀態(tài)。JavaScript 語句執(zhí)行的完成狀態(tài),我們用一個標準類型來表示:Completion Record。

      Completion Record 表示一個語句執(zhí)行完之后的結(jié)果,它有三個字段:

      • [[type]] 表示完成的類型,有 break continue return throw 和 normal 幾種類型;如果返回的type是normal,那么語句將會順序執(zhí)行。

      • [[value]] 表示語句的返回值,如果語句沒有,則是 empty;只有表達式語句會產(chǎn)生 [[value]]。

      • [[target]] 表示語句的目標,通常是一個 JavaScript 標簽。當(dāng)在循環(huán)語句中,結(jié)合break/continue可以跳出多層循環(huán)。

      outer: while(true) {
          inner: while(true) {
              break outer;
          }
      }
      console.log("finished")

      在任何一個js語句之前都可以加一個標簽。

          firstStatement: var i = 1;

      控制語句跟 break 、continue 、return 、throw四種類型與控制語句兩兩組合產(chǎn)生的效果。

      • 消費就是在當(dāng)前語句中結(jié)束了。

      穿透就是繼續(xù)執(zhí)行下一條語句。

      js潛在規(guī)則有哪些

      文法

      文法 = 詞法 + 語法。

      詞法

      JavaScript 源代碼中的輸入可以這樣分類:

      WhiteSpace 空白字符

      LineTerminator 換行符

      Comment 注釋

      Token 詞

      • IdentifierName 標識符名稱,典型案例是我們使用的變量名,注意這里關(guān)鍵字也包含在內(nèi)了。

      • Punctuator 符號,我們使用的運算符和大括號等符號。

      • NumericLiteral 數(shù)字直接量,就是我們寫的數(shù)字。 為什么12.toString會報錯?

      十進制的 Number 可以帶小數(shù),小數(shù)點前后部分都可以省略,但是不能同時省略。12.被當(dāng)成一個詞。如果想讓表達式正常運行,我們可以讓.成為一個詞。

          12. toString()
      • StringLiteral 字符串直接量,就是我們用單引號或者雙引號引起來的直接量。

      字符串中其他必須轉(zhuǎn)義的字符是\和所有換行符。

      • Template 字符串模板,用反引號`括起來的直接量。

      • RegularExpressionLiteral

      正則表達式有自己的語法規(guī)則,在詞法階段,僅會對它做簡單解析。

      語句是否需要加分號

      自動插入分號規(guī)則其實獨立于所有的語法產(chǎn)生式定義,它的規(guī)則說起來非常簡單,只有三條。

      • 要有換行符,且下一個符號是不符合語法的,那么就嘗試插入分號。

      • 有換行符,且語法中規(guī)定此處不能有換行符,那么就自動插入分號。

      • 源代碼結(jié)束處,不能形成完整的腳本或者模塊結(jié)構(gòu),那么就自動插入分號。

      no LineTerminator here規(guī)則

      這個規(guī)則與自動插入分號的第二條規(guī)則緊密相關(guān)。

      js潛在規(guī)則有哪些

      腳本和模塊

      腳本是可以由瀏覽器或者 node 環(huán)境引入執(zhí)行的,而模塊只能由 JavaScript 代碼用 import引入執(zhí)行。

      從概念上,我們可以認為腳本具有主動性的 JavaScript 代碼段,是控制宿主完成一定任務(wù)的代碼;而模塊是被動性的 JavaScript 代碼段,是等待被調(diào)用的庫。

      直接 import 一個模塊,只是保證了這個模塊代碼被執(zhí)行,引用它的模塊是無法獲得它的任何信息的。帶 from 的 import 意思是引入模塊中的一部分信息,可以把它們變成本地的變量。

      通過export default導(dǎo)出的值,和導(dǎo)入文件的變量不是實時綁定的。導(dǎo)出文件的變量改變不會影響導(dǎo)入變量的變化。

      聲明提升

      預(yù)處理階段,var 和函數(shù)聲明的作用能夠穿透一切語句結(jié)構(gòu),它只認腳本、模塊和函數(shù)體三種語法結(jié)構(gòu)。

      函數(shù)聲明提升和var變量聲明提升的區(qū)別

      函數(shù)聲明能穿過if等語句,但是只是在全局創(chuàng)建一個同名的變量賦值為undefined,并沒有把函數(shù)體提升。

          console.log(foo); // undefined
          if(true) {
              function foo(){}
          }
          // 因為一般函數(shù)都是整體提升的。
          var a = 1;
          function foo() {
              console.log(a); // undefined
              if(false) {
                  var a = 2;
              }
          }
          foo();

      解析HTML

      編譯階段。會將html標簽拆分成一個個token(表示最小的有意義的單元), 種類大約只有標簽開始、屬性、標簽結(jié)束、注釋、CDATA 節(jié)點幾種。

      實現(xiàn)分詞,又用到了狀態(tài)機。用狀態(tài)機做詞法分析,其實正是把每個詞的“特征字符”逐個拆開成獨立狀態(tài),然后再把所有詞的特征字符鏈合起來,形成一個聯(lián)通圖結(jié)構(gòu)。 其中每一個狀態(tài)函數(shù)都返回一個狀態(tài)函數(shù),做狀態(tài)遷移。

      把html元素分成若干詞后,我們就可以構(gòu)建dom樹了。這個過程是使用棧來實現(xiàn)的。我們把每個解析的詞加入到棧中,當(dāng)接收完所有輸入,棧頂就是最后的根節(jié)點。

      對于 Text 節(jié)點,我們則需要把相鄰的 Text 節(jié)點合并起來,我們的做法是當(dāng)詞(token)入棧時,檢查棧頂是否是 Text 節(jié)點,如果是的話就合并 Text 節(jié)點。

      可以點擊這里查看解析規(guī)則

      github上別人寫了一個簡易的解析器

      排版。

      • 瀏覽器對行的排版,一般是先行內(nèi)布局,再確定行的位置,根據(jù)行的位置計算出行內(nèi)盒和文字的排版位置。

      • 塊級盒比較簡單,它總是單獨占據(jù)一整行,計算出交叉軸方向的高度即可。

      • 浮動元素排版,float 元素非常特別,瀏覽器對 float 的處理是先排入正常流,再移動到排版寬度的最左 /最右(這里實際上是主軸的最前和最后)。

      • 絕對定位元素。完全跟正常流無關(guān)的一種獨立排版模式,逐層找到其父級的 position 非 static 元素即可。

      渲染。

      瀏覽器中渲染這個過程,就是把每一個元素對應(yīng)的盒變成位圖。 這里的元素包括 HTML 元素和偽元素,一個元素可能對應(yīng)多個盒(比如 inline 元素,可能會分成多行)。每一個盒對應(yīng)著一張位圖。

      渲染過程,是不會把子元素繪制到渲染的位圖上的,這樣,當(dāng)父子元素的相對位置發(fā)生變化時,可以保證渲染的結(jié)果能夠最大程度被緩存,減少重新渲染。

      合成。

      合成的過程,就是為一些元素創(chuàng)建一個“合成后的位圖”(我們把它稱為合成層),把一部分子元素渲染到合成的位圖上面。

      繪制。

      繪制過程,實際上就是按照 z-index 把合成位圖依次繪制到屏幕上。

      DOM API

      DOM API 大致會包含 4 個部分。

      • 節(jié)點:DOM 樹形結(jié)構(gòu)中的節(jié)點相關(guān) API。

      • 事件:觸發(fā)和監(jiān)聽事件相關(guān) API。

      • Range:操作文字范圍相關(guān) API。

      • 遍歷:遍歷 DOM 需要的 API。

      js潛在規(guī)則有哪些

      節(jié)點

      元素在DOM樹中關(guān)系api

      • parentNode

      • childNodes

      • firstChild

      • lastChild

      • nextSibling

      • previousSibling

      操作 DOM 樹的API

      • appendChild

      • insertBefore

      • removeChild

      • replaceChild

      一些高級 API

      • compareDocumentPosition 是一個用于比較兩個節(jié)點中關(guān)系的函數(shù)。

      • contains 檢查一個節(jié)點是否包含另一個節(jié)點的函數(shù)。這個方法一般用于做一些點擊判斷,然后關(guān)閉一些dom的功能。

      • isEqualNode 檢查兩個節(jié)點是否完全相同。

      • isSameNode 檢查兩個節(jié)點是否是同一個節(jié)點,實際上在 JavaScript 中可以用“===”。

      • cloneNode 復(fù)制一個節(jié)點,如果傳入?yún)?shù) true,則會連同子元素做深拷貝。

      創(chuàng)建DOM的api

      • createElement

      • createTextNode

      • createCDATASection

      • createComment

      • createProcessingInstruction

      • createDocumentFragment

      • createDocumentType

      操作屬性的api

      • getAttribute

      • setAttribute

      • removeAttribute

      • hasAttribute 如果你喜歡 property 一樣的訪問 attribute,還可以使用 attributes 對象,比如document.body.attributes.class =“a”等效于document.body.setAttribute(“class”,“a”)。

      查找元素api

      • querySelector

      • querySelectorAll

      • getElementById

      • getElementsByName

      • getElementsByTagName

      • getElementsByClassName

      我們需要注意,getElementById、getElementsByName、getElementsByTagName、getElementsByClassName,這幾個 API 的性能高于 querySelector。

      新增加的節(jié)點會被添加到非querySelector, querySelectorAll查詢出來的對象上的。

      遍歷

      • createNodeIterator

      • createTreeWalker

      Range

      Range API 表示一個 HTML 上的范圍,這個范圍是以文字為最小單位的,所以 Range 不一定包含完整的節(jié)點。

      具體請看這里

      DOM中的位置

      全局尺寸信息

      js潛在規(guī)則有哪些

      我們獲取寬高的對象應(yīng)該是“盒”,于是 CSSOM View 為 Element 類添加了兩個方法:

      • getClientRects()。返回一個列表,里面包含元素對應(yīng)的每一個盒所占據(jù)的客戶端矩形區(qū)域,這里每一個矩形區(qū)域可以用 x, y, width, height 來獲取它的位置和尺寸。

      • getBoundingClientRect()。它返回元素對應(yīng)的所有盒的包裹的矩形區(qū)域,需要注意,這個 API 獲取的區(qū)域會包括當(dāng) overflow 為visible 時的子元素區(qū)域。

      這兩個 API 獲取的矩形區(qū)域都是相對于視口的坐標,這意味著,這些區(qū)域都是受滾動影響的。

      事件

      事件捕獲的由來?

      我們操作元素時,都是通過輸入設(shè)備來做到的,點擊事件來自觸摸屏或者鼠標,鼠標點擊并沒有位置信息,但是一般操作系統(tǒng)會根據(jù)位移的累積計算出來,跟觸摸屏一樣,提供一個坐標給瀏覽器。把這個坐標轉(zhuǎn)換為具體的元素上事件的過程,就是捕獲過程了。

      建議這樣使用冒泡和捕獲機制:默認使用冒泡模式,當(dāng)開發(fā)組件時,遇到需要父元素控制子元素的行為,可以使用捕獲機制。

      事件處理函數(shù)不一定是函數(shù),也可以是個 JavaScript 具有 handleEvent 方法的對象。

      var o = {
          handleEvent: event => console.log(event)
      }
      document.body.addEventListener("keydown", o, false);

      自定義事件。DOM API 中的事件并不能用于普通對象,所以很遺憾,我們只能在 DOM 元素上使用自定義事件。

          var evt = new Event("look", {
              "bubbles":true, 
              "cancelable":false
          });
          document.dispatchEvent(evt); // 調(diào)用自定義事件

      性能優(yōu)化

      js潛在規(guī)則有哪些

      到此,相信大家對“js潛在規(guī)則有哪些”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

      向AI問一下細節(jié)

      免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

      js
      AI