讀高性能JavaScript編程 第二章 讓我知道了代碼為什麼要這樣寫

来源:http://www.cnblogs.com/zhuwansu/archive/2016/12/01/6118615.html
-Advertisement-
Play Games

代碼為什麼要這樣寫? 而不這樣? 很明顯 我們都知道第一個性能要比第二個好,為什麼呢? 首先要瞭解 js引擎的 Data Access 數據訪問。這裡只說 非優化的js引擎。 1、訪問 Literal values 直接量 eg:字元串,數字,布爾值,對象,數組,函數,正則表達式,具有特殊意義的空值 ...


代碼為什麼要這樣寫?

function initUI(){ 
var doc = document, 
bd = doc.body, 
links = doc.getElementsByTagName_r("a"),

i = 0, 
len = links.length; 
while(i < len){ 
update(links[i++]); 
} 
doc.getElementById("go-btn").onclick = function(){ 
start(); 
}; 
bd.className = "active"; 
}

 而不這樣?

 

//avoid
function initUI(){ var bd = document.body, links = document.getElementsByTagName_r("a"), i = 0, len = links.length; while(i < len){ update(links[i++]); } document.getElementById("go-btn").onclick = function(){ start(); }; bd.className = "active"; }

  很明顯 我們都知道第一個性能要比第二個好,為什麼呢?

首先要瞭解 js引擎的 Data Access  數據訪問。這裡只說 非優化的js引擎。

1、訪問 Literal values 直接量 eg:字元串,數字,布爾值,對象,數組,函數,正則表達式,具有特殊意義的空值,以及未定義。

2、訪問 Variables   變數        var創建用於存儲數據值。

3、訪問 Array items   數組項  具有數字索引的數組對象

4、訪問 Object members   對象成員 具有字元索引的js對象

從上面的例子我們也能猜到 訪問 局部變數比訪問對象成員和數組項更快。

那麼為什麼訪問對象成員 和數組項要慢呢? 書中說的很詳細,我只介紹一下自己的理解和摘錄。

  大多數 JavaScript 代碼以面向對象的形式編寫。無論通過創建自定義對象還是使用內置的對象,諸如

文檔對象模型(DOM)和瀏覽器對象模型(BOM)之中的對象。 

 對象成員包括屬性和方法,在 JavaScript 中,二者差別甚微。對象的一個命名成員可以包含任何數據類
型。既然函數也是一種對象,那麼對象成員除傳統數據類型外,也可以包含一個函數。當一個命名成員引
用了一個函數時,它被稱作一個“方法”,而一個非函數類型的數據則被稱作“屬性”。

  JavaScript中的對象是基於原形的。原形是其他對象的基礎,定義並實現了一個新對象所必須具有的成
員。這一概念完全不同於傳統面向對象編程中“類”的概念,它定義了創建新對象的過程。原形對象為所有
給定類型的對象實例所共用,因此所有實例共用原形對象的成員。

  一個對象通過一個內部屬性綁定到它的原形。Firefox,Safari,和 Chrome 向開發人員開放這一屬性,稱
作__proto__;其他瀏覽器不允許腳本訪問這一屬性。任何時候你創建一個內置類型的實例,如 Object 或
Array,這些實例自動擁有一個 Object 作為它們的原形。

  因此,對象可以有兩種類型的成員:實例成員(也稱作“own”成員)和原形成員。實例成員直接存在於
實例自身,而原形成員則從對象原形繼承。

這些很難理解,但是看了後很透徹。緊接著最後一句話,你調用實例成員肯定比調用原型成員要快,比如   

var book = { 
  title: "High Performance JavaScript", 
  publisher: "Yahoo! Press" 
}; 
alert(book.toString());
alert(book.title);

 book 本身是沒有toString 的 但是程式編譯並不報錯,因為toString是它的原型成員。

 假設book.title === book.toString()  book.toString() 依舊比 book.title 更慢。 

 

book創建後 其 原型綁定在 _proto_ 內部屬性上 , 觀察這個原型可以看到 toString() 這個標識符 book 本身並沒有toString這個function

而是從它的原型上繼承得來。其實在調用 book.title 的時候,js引擎如何知道 title是否是未定義的呢?

在函數執行過程中,每遇到一個變數,標識符識別/解析這些變數的方法是按順序搜索運行期上下文作用域鏈查找同名標識符,如果找不到就是未定義,

所以通常返還未定義註定是檢索了整個作用域鏈。正是這種搜索影響了性能。

如果在作用域鏈里 toString 比 title更靠後那麼就 可以確定title 會比toString更先找到。

什麼是運行期上下文,什麼是作用域鏈?

  每一個 JavaScript 函數都被表示為對象。進一步說,它是一個函數實例。函數對象正如其他對象那樣,
擁有你可以編程訪問的屬性,和一系列不能被程式訪問,僅供 JavaScript 引擎使用的內部屬性。其中一個
內部屬性是[[Scope]],由ECMA-262 標準第三版定義。

  內部[[Scope]]屬性包含一個函數被創建的作用域中對象的集合。此集合被稱為函數的作用域鏈,它決定
哪些數據可由函數訪問。此函數作用域鏈中的每個對象被稱為一個可變對象,每個可變對象都以“鍵值對”

的形式存在當一個函數創建後,它的作用域鏈被填充以對象,這些對象代表創建此函數的環境中可訪問
的數據。例如下麵這個全局函數:

function add(num1, num2){
var sum = num1 + num2;
return sum;
}

圖中 只給出了 全局對象 在作用域鏈的位置,並沒有不包括所有的。

註意:scope chain (作用域鏈) 里的 這些可變對象都是以鍵值對的形式存在的。

 

 圖中的 activation object 被譯為 激活對象 此對象是在 此add函數被調用時創建的  例如:運行此代碼  var s = add(1,2);

運行此段代碼時會創建一個內部對象(之前已經提到,形如[[xxx]])稱作   execution context 就是上面講的運行期上下文。 它定義了一個函數運行是的環境。

而值得一提的是 對函數的每次運行而言,每個運行期上下文都是獨一的,所以多次調用同一個函數就會導致多次創建運行期上下文。當函數執行完畢,運行期上下文就被銷毀.

運行期上下文也是有scope chain的。這個作用域鏈被用於 標識符解析 。

當 運行期上下文被創建的時候 它的作用域鏈被初始化 連同 函數的[[scope]]屬性 中所包含的對象 會按照順序被覆制到 運行期上下文的作用域鏈里。最後你看到的就是

激活對象了。 如圖它被推向了作用域鏈的前端。 而標識符識別是從前到後的。

簡單講最終結果是 toString 標識符所在的位置 是作用域的後端 而 title 標識符實在作用域鏈的更前端,所以toString會更慢。

回到最開始的話題你會發現 你僅僅是 把 document 緩存到一個 局部變數 doc 里就可以減少 一次或者更多次非常深的 標識符掃描。

同時可以意識到 成員嵌套越深掃描作用域鏈越深。成員嵌套越深,訪問速度越慢。location.href總是快於 window.location.href

這有點類似於 尾遞歸的作用了。

 書中詳細說了 標識符性能、 動態作用域、閉包可能導致記憶體泄漏、改變作用域鏈。以及有關原型、原型鏈。總之受益匪淺。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、HTML5新增屬性 1.1、contextmenu contextmenu的作用是指定右鍵菜單。 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div id="div1" ...
  • 本文介紹了css3中的box-sizing屬性,在這之前讀者需要預備知識width的範圍。 瀏覽器的支持情況 box-sizing屬性 box-sizing屬性可以有三個值:content-box(defalut),border-box屬性。 <style> div{ width:100px; he ...
  • 1)在折線圖中,有時我們不想讓太多折線顯示,那麼就隱藏,點擊legend區域文字再顯示。 比如我們要隱藏的折線叫”聯盟廣告“,代碼如下 在series中依然有它相關的數據 這樣,當我們點擊的時候,折線就顯示了。 2)折線坐標軸太粗,不夠細?顏色不好看? 那麼,可以這樣改 y軸也同理。 3)分隔線顏色 ...
  • 目錄 一、HTML5概要 1.1、為什麼需要HTML5 1.2、什麼是HTML5 1.3、HTML5現狀及瀏覽器支持 1.4、HTML5特性 1.5、HTML5優點與缺點 1.5.1、優點 1.5.2、缺點 1.6、HTML5效果展示 1.7、HTML5學習與開發工具 1.7.1、基礎要求 1.7. ...
  • 因為項目需要,要求實現類似力導圖效果的圖,我就瞄上了echarts。 註意事項1:由於我的項目要部署到內網,所以js文件要在本地,網上大多力導圖都是echarts2的,而其又依賴zrender基礎庫,下載的echarts2是2.2.7版本,但是去zrender官網下載的2.1版本,用起來說版本最低要 ...
  • 前言 更好的閱讀體驗請:我的微信小程式入門踩坑之旅 小程式出來也有一段日子了,剛出來時也留意了一下。不過趕上生病,加上公司里也有別的事,主要是自己犯懶,就一直沒做。這星期一,趕緊趁著這股熱乎勁,也不是很忙,終於磨磨唧唧的寫了個小demo,(當然還有好多介面沒有使用)。 預計閱讀時間:5min 正文 ...
  • 最近的項目在使用AngulaJs,對JS代碼的測試問題就擺在了面前。通過對比我們選擇了 Karma + jasmine ,使用 Jasmine做單元測試 ,Karma 自動化完成,當然瞭如果使用 Karma + jasmine 前提是必須安裝 Nodejs。 安裝好 Nodejs ,使用 npm 安 ...
  • 正則表達式: 匹配(說明): 使用說明: (1)、地址必須以http/https/ftp/ftps開頭; (2)、地址不能包含雙位元組符號或非鏈接特殊字元。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...