分享

JavaScript 客戶端開篇

 ipilipala 2017-01-14

參考資料

零、引言

  本人垃圾,害人無數。本篇主要為Web瀏覽器中JavaScript相關要點簡介,包括客戶端 JavaScript 算法概述,JavaScript程序的執行原理,瀏覽器的兼容性和互用性,可訪問性和安全性等。

一、客戶端 JavaScript

1. 全局對象 Window

  • Window 對象是所有客戶端JavaScript特性和API的主要接入點。它表示Web瀏覽器中的一個窗口或窗體,並且可以用標識符 window 來引用它。我們直接使用語句就能實現的瀏覽器操作,其實就是封裝在 Window 頂層對象的方法屬性,如下:
//  設置location屬性,從而跳轉到新的web頁面
window.location = "http:www.baidu.com";
//  使用setTimeout方法延時2s執行函數
setTimeout(
     function() {
        alert("hello world");    // alert也是瀏覽器內置方法
    }, 2000
)
  • Window 對象還定義了很多其它重要的對象和方法,後續文章會繼續整理,當然,可以使用 console.log(window); 查看具體某一瀏覽器擁有的對象及方法。

2. BOM & DOM

  • 經常會在各種地方看到 BOMDOM 這兩個詞彙,那麼這兩個到底是什麼呢? BOM 即 Browser object model, DOM 即 Document object model,二者的關係從以下的關係圖可以直觀看出,document 對象是 window 對象的一個重要屬性。

BOM DOM 關係圖
  • DOM:web文檔裡的JavaScript。JavaScript程序可以通過 Document 對象和它包含的 Element 對象遍歷管理文檔內容。它可以通過操縱CSS的樣式和類,修改文檔內容的呈現,可以通過註冊適當的事件處理程序來定義文檔元素的行為。內容,呈現和行為的組合,叫做動態HTML或DHTML。Web文檔中因儘量避免使用JavaScript,因為JavaScript的作用是增強用戶體驗,而不是直白的傳遞信息。如通過以下方式:
    • 創建動畫和其他視覺效果,巧妙地引導和幫助用戶進行頁面導航。
    • 對表格的列進行分組,讓用戶更容易找到所需要的。
    • 隱藏某些內容,當用戶「深入」到內容裡時,再逐漸展示詳細的信息。
  • BOM:web應用裡的JavaScript。對於Web應用來說,除了內容,呈現和操作API之外,還依賴了Web瀏覽器環境提供的更基礎的服務。現在,瀏覽器已經漸漸變成一個簡單的操作系統。雖然javascript引擎是單線程的,但是瀏覽器是多線程的,在一個瀏覽器進程中一般有四個線程:javascript引擎線程渲染引擎線程瀏覽器事件線程http請求線程
傳統操作系統 Web瀏覽器
允許組織桌面和文件夾裡的圖標 允許在工具欄和文件夾裡組織書籤
可以在一個窗口裡運行多個應用 可以在一個標籤裡顯示多個文檔
定義了很多頂層API,提供繪圖,保存文件等功能 定義了底層網絡API,保存數據和繪製圖像

3. 事件處理程序

  • 當腳本所在的HTML文件被載入瀏覽器時,這個腳本裡的JavaScript代碼只會執行一次。為了可交互,JavaScript程序必須定義事件處理程序(異步編程模型)——Web瀏覽器先註冊JavaScript函數,並在之後調用它作為事件的響應。例如:
----html----
<input type="submit" value="submit" />
----js----
var obj = document.getElementByTagName("input");
// 註冊事件處理程序
obj.onclick = function() {
    alert("Please check out the info you fill in");
}

4. 常用對象(Window 對象後續文章跟進)

(1)Array 對象 對數組的內置支持

  • 構造函數
new Array();
new Array(size);  // size設置數組的長度
new Array(element0, element1, element2...);  // element0, element1 位數組中的參數列表
  • 直接量語法
var a = [1, true, 'abc'];
var b = [a[0], a[0]*2, f(x)];
  • 屬性
    length:一個可讀/寫的整數,用來指明數組中的元素個數。
  • 方法
    參考 數組方法MDN array

(2)Object 對象 包含所有JavaScript對象的特性的超類

  • 構造函數
new Object();
new Object(value);  // 這個可選的參數指定一個原始的JavaScript值——一個數字、布爾值或字符串,這些值將分別轉換為一個Number、Boolean或String對象。
  • 直接量語法:
var a = {
    type : "fruit",
    name : "apple",
    number : 1,
    isPicked : true,
            // 空對象  
}
  • 屬性
    constructor:引用當前對象的構造函數。
  • 方法
    可參考 MDN Object
// 常用的兩個方法, 引用以上定義的a對象舉例

if (a.hasOwnProperty('type')) {    // 本地定義的屬性,而不是繼承而來。Object對象的所有方法和行為都被其他對象繼承,因此可通過此方法進行區分
    console.log("true");    // => true
    console.log(Object.getOwnPropertyNames(a));    // 返回一個包含指定對象的所有非繼承屬性名的數組
}

(3)String 對象 字符串支持

  • 構造函數
new String(s);    // 構造函數
function String(s);    // 轉換函數
  • 屬性
    length:該字符串中的字符數。
  • 方法
// 常用方法舉例

var str = "i have an apple";
console.log(str.charAt(3));                // => a
console.log(str.concat(" ,too"));          // => i have an apple ,too
console.log(str.includes("o"));            // => false
console.log(str.endsWith("e"));            // => true,對應有startsWidth()
console.log(str.indexOf("a"));             // => 3,第一個索引值
console.log(str.lastIndexOf("a"));         // => 10,最後一個索引值
console.log(str.slice(2,6));               // => have
console.log(str.substr(2,5));              // => have
console.log(str.substr(2,5).toLocaleUpperCase());    // HAVE
console.log(str.split(" "));               // ["i","have","an","apple"],分割成數組形式

可參考 MDN String

(4)Math 對象 數學函數和常量

  • 常量
Math.E    // 自然對數的底數
Math.PI   // 常量π
Math.SQRT2  // 2的平方根
  • 靜態函數
Math.abs()  // 計算絕對值
Math.ceil()  // 對一個數字向上取整
Math.floor()  // 對一個數字向下取整
Math.exp()  // 計算e的乘方
Math.log()  // 計算自然對數
Math.max()  // 返回兩個數中較大的那個
Math.min()  // 返回兩個數中較小的那個
Math.random()  // 計算一個隨機數 [0,1]
  • 注意:Math 不是對象的類(不像DateString),沒有 Math() 構造函數,類似於 Math.sin() 這樣的函數只是簡單的函數,而不是對某個對象進行操作的方法。

(5)Date 對象 操作日期和時間

  • 構造對象
// 四種不同格式,參數意義查看MDN文檔,後邊的實例比較直觀易懂
new Date();
new Date(value);
new Date(dateString);
new Date(year, month[, day[, hour[, minutes[, seconds[, milliseconds]]]]]);
  • 方法
console.log(new Date());        // 根據當前日期和時間創建一個Date對象
console.log(new Date(1000));    // 需要的時間與1970年1月1日午夜(UTC)之間的毫秒數
var myDate = new Date("Aug 9, 1995");        // 一個以字符串形式定義的日期

console.log(myDate.getDate());            // 獲取本地日期 => 9
console.log(myDate.getUTCDate());        // 獲取世界日期 => 8

更多可參考 MDN Date

二、JavaScript程序的執行

0. 概述

  • JavaScript程序的執行有兩個階段。在第一個階段,載入文檔內容,並執行 <script> 元素裡的代碼,腳本通常會按照 <script> 在文檔裡的出現順序執行,所有腳本裡的JavaScript代碼都是從上往下,按照它在條件、循環以及其他控制語句中的出現順序執行。
// 使用jquery語法設置<a>的字體顏色為紅色
<script>
$("a").css("color","red");
</script>
// 引入jquery庫
<script src="jquery.js"></script>

// 通過分析<script>標籤的位置可知,在第一階段加載過程中,jquery庫未引入,便執行使用jquery語法書寫的代碼,則該代碼會報錯
  • 當文檔載入完成,並且所有腳本執行完成後,JavaScript執行就進入它的第二階段。這個階段是異步的,而且是由事件驅動的。在事件驅動階段,Web瀏覽器調用事件處理程序函數(由第一階段裡執行的腳本指定的HTML事件處理程序,或之前調用的事件處理程序來定義),來響應異步發生的事件。
----html----
<input type="submit" value="submit" />
----js---- 在第一階段加載完代碼後註冊HTML事件處理程序
var obj = document.getElementByTagName("input");
// 註冊事件處理程序
obj.onclick = function() {
    alert("Please check out the info you fill in");
}
----當用戶點擊submit按鈕時,響應事件----

1. 同步、異步和延遲的腳本

  • 當HTML解析器遇到 <script> 元素時,它默認必須先執行腳本(腳本中的代碼可能操作DOM等),然後再恢覆文檔的解析和渲染。這對於內聯腳本沒什麼問題,但如果腳本源代碼是一個由 src 屬性指定的外部文件,這意味著腳本後面的文檔部分在下載和執行腳本之前,不會被瀏覽器引擎解析為DOM樹,JavaScript代碼會「阻塞」頁面UI的渲染。
<head>
    <script src="demo.js"></script>    // 假設這個文件很大,則body部分很久之後才渲染
</head>
<body>
    ...
</body>
  • 腳本在默認情況下是同步和阻塞的。可以通過以下方式改變腳本的執行方式。(異步是JavaScript實現非阻塞的主要方式)
<script defer src="deferred.js"></script>    // 非阻塞
<script async src="async.js"></script>       // 異步
// 當<script>標籤同時擁有這兩個屬性,支持兩個屬性的瀏覽器會遵從async並忽略defer

2. 事件驅動的JavaScript

  • 三要素:事件都有名字,比如 clickchangeload 等,指示發生事件的通用類型。事件還有目標,它是一個對象,並且事件就是在這之上發生的,比如 readystatechange 事件發生在 XMLHttpRequest 對象上。事件的響應程序叫做 「事件處理程序」、「事件監聽器」 或 「回調」 ,然後註冊這個函數,當事件發生時調用它。
  • 事件處理機制:事件冒泡、事件傳播、事件捕獲、事件委託。(參考 事件機制(博文))。
  • 一個對象註冊多個事件監聽器,可使用 addEventListener()attachEvent() (IE8及以下)。

3. 客戶端JavaScript線程模型

  • 操作系統相關概念補充

    • 進程(process):是指在系統中正在運行的一個應用程序,是系統資源分配的基本單位,在內存中有其完備的數據空間和代碼空間,擁有完整的虛擬空間地址。一個進程所擁有的數據和變量(如 Window 對象)只屬於自己。在Web瀏覽器中,一個窗口即一個進程。同個瀏覽器不同窗口即有多個進程。進程間的運行關係由瀏覽器內核控制。
    • 線程(thread):是進程內相對獨立的可執行單元,所以也被成為輕量進程(lightweight process);是操作系統進行任務調度的基本單元。它與父進程的其他線程共享該進程所擁有的全部代碼空間和全局變量,但擁有獨立的堆棧(即局部變量對於線程來說是私有的)。
    • 聯繫:進程和線程都具有就緒、阻塞和運行三種基本狀態。一個進程至少擁有一個線程——主線程,也可以擁有多個線程;一個線程必須有一個父進程。多個進程可以並發執行;一個線程可以創建和撤銷另一個線程;同一個進程中的多個線程之間可以並發執行。
  • Web瀏覽器是單線程執行的(編程簡單,避免不同線程之間衝突 如一個線程刪除DOM節點,另一個線程增加DOM節點,這兩個節點是一樣的,那麼哪個先執行呢)。Web瀏覽器有JavaScript引擎線程、渲染引擎線程、瀏覽器事件線程、http請求線程。當其中一個線程執行時,其他的線程就會處於 「停滯」 狀態,例如 JavaScript 引擎線程執行時,渲染引擎線程就不會同時執行,即前面所說的 DOM 渲染延遲。

4. 客戶端 JavaScript 的時間線

  • Web瀏覽器創建 Document 對象,並且開始解析 Web 頁面,解析 HTML 元素和它們的文本內容後添加到 Elemenr 對象和 Text 節點到文檔中。(readystate 屬性為 loading
  • 加載並執行同步加載的腳本
  • 加載並執行 async 屬性的腳本
  • 文檔解析完成, document.readyState 屬性變成 interactive
  • 加載並執行 defer 屬性的腳本
  • 瀏覽器在 Document 對象上觸發 DOMContentLoaded 事件,這標誌著程序執行從同步腳本執行階段轉換到了異步事件驅動階段
  • 文檔已經完全解析,但是瀏覽器還可能在等待圖片等內容的載入。當這些內容完成載入時, document.readyState 屬性改變為 complete , Web瀏覽器觸發 window 對象上的 load 事件
  • 從即刻起,會調用異步事件,以異步響應用戶輸入事件、網絡事件、計時器過期等

三、兼容性和互用性

  • 主要可以歸納為以下三類
    • 演化:Web標準規範會倡導一個新的特性或 API 。如果看起來有用,瀏覽器開發商實現它, 開發者開始依賴新特性開發。當然,開發者要在舊瀏覽器大量用戶和新瀏覽器少量用戶之間做出權衡。
    • 未實現: 主要是不同瀏覽器廠商對新特性實現的必要性的觀點不同。
    • bug: 每個瀏覽器都存在一些bug。

四、可訪問性和安全性

  • 可訪問性:考慮不同用戶群體的操作習慣
  • 安全性:
    • JavaScript 程序沒有寫入或刪除客戶端文件權限
    • JavaScript 程序打開/關閉另一個窗口受限
    • 同源策略

END:Question

  1. alert("something"); 不是JavaScript語言核心的輸出語句,為什麼在瀏覽器運行能達到輸出效果?
  2. BOM與DOM的關係,DOM常用來做什麼?瀏覽器四個線程?
  3. 事件處理程序遵循了JavaScript異步編程模型的思想,那麼什麼是異步,什麼是同步?(拓展:阻塞與非阻塞)
  4. 常用對象的屬性及方法?
  5. <script> 標籤的先後順序,以及放在 <head></head><body></body> 的不同?
  6. 事件驅動三要素、處理機制?
  7. JavaScript是單線程還是多線程,同步還是異步,阻塞還是非阻塞?

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多