iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 11
7
Modern Web

重新認識 JavaScript系列 第 11

重新認識 JavaScript: Day 11 前端工程師的主戰場:瀏覽器裡的 JavaScript

花了好幾天的時間,「重新認識 JavaScript: JS 基礎篇」終於告一段落了。
如果讀者跟著我一路看到這裡,相信各位對 JavaScript 這門程式語言已經有了基本的理解。

從今天開始,我們要進入「前端工程師的主戰場:瀏覽器裡的 JavaScript」的部分囉。


我說那個網頁呢? 談 JavaScript 與網頁前端的關係

在許多的網頁前端教學或是文章書籍當中,你可能常常聽到這樣的說法:「HTML、CSS 與 JavaScript 是網頁前端三大要素」

  • HTML 負責資料與結構
  • CSS 負責樣式與呈現
  • JavaScript 負責行為與互動

https://ithelp.ithome.com.tw/upload/images/20171214/20065504RimKuAje7L.png

這樣的說法基本上沒有錯。

那麼,如果你跟我當年學 JavaScript 也有一樣的疑問:變數型別物件迴圈流程控制函式... 表面上看似基礎都學會了,但...

我還是不知道怎麼透過 JavaScript 在網頁上輸出 "Hello World!" 啊!

https://media.giphy.com/media/3oEduPs99YeI3xBD3y/giphy.gif

那麼相信看完今天的分享,我保證你一定可以透過 JavaScript 在網頁上輸出 "Hello World!" (咦)


瀏覽器裡的 JavaScript

嚴格來說,JavaScript (或者說 ECMAScript 標準) 並沒有提供網頁的操作方法。

事實上,前端開發者在網頁的操作方法都是由 JavaScript 的執行平台,也就是「瀏覽器」提供的。 這些操作方法基本上會分別由這兩種物件所擁有:「BOM」與「DOM」。

所以廣泛來說,在瀏覽器上的 JavaScript 實際上包含了:

  • JavaScript 核心 (以 ECMAScript 標準為基礎)
  • BOM (Browser Object Model,瀏覽器物件模型)
  • DOM (Document Object Model,文件物件模型)

以上這三個部分。

由於「BOM」與「DOM」是由瀏覽器執行環境所提供。
換句話說,在 node 環境下的 JavaScript 就不會有這兩個部分。

前端開發者就是透過 JavaScript 去呼叫 BOM 與 DOM 提供的 API,進一步透過它們去控制瀏覽器的行為與網頁的內容。

那麼接下來我們就來介紹「BOM」與「DOM」。


BOM 是什麼?

BOM (Browser Object Model,瀏覽器物件模型),是瀏覽器所有功能的核心,與網頁的內容無關。

在早期沒有制定標準規範的時候,各家瀏覽器廠商幾乎各自在自家瀏覽器上實作功能,非常混亂。 直到最近幾年, W3C 把各家瀏覽器都有實作的部分,以及確定已經(或未來會) 加入的功能,統一集合起來納入了 HTML5 的標準中,這也就是我們現在看到的 BOM API 的實作。

BOM 也有人非正式地稱它為 「Level 0 DOM」。 因為它在 DOM level 1 標準前就已存在,而不是真的有文件去規範這些,所以「Level 0 DOM」與「BOM」兩者實際上指的是同一個東西。


BOM 的核心 window 物件

https://ithelp.ithome.com.tw/upload/images/20171214/20065504EIG4UYcuGE.png

BOM 的核心是 window 物件。

window 物件提供的屬性主要為 documentlocationnavigatorscreenhistory 以及 frames

在瀏覽器裡的 window 物件扮演著兩種角色:

  • ECMAScript 標準裡的「全域物件」 (Global Object)
  • JavaScript 用來與瀏覽器溝通的窗口

全域物件的部分我們之前已經談過,凡是在「全域作用範圍」內宣告的變數、物件、函式等,都會自動變成「全域物件」的屬性。 通常這樣的變數,我們會稱它們叫做「全域變數」,可以透過 window.xxx 的方式取得它們。

var a = 10;
console.log( window.a );    // 10

除此之外,在「全域作用範圍」宣告的全域變數還有一個特性,就是無法使用 delete 關鍵字來移除:

var a = 10;
console.log( window.a );    // 10

delete window.a;            // false
console.log( window.a );    // 10

但若是直接透過指定 window 物件的屬性則可以:

window.a = 10;
console.log( window.a );    // 10

delete window.a;            // true
console.log( window.a );    // undefined

現在我們已經知道了「全域物件」是怎麼回事了,那麼 window 物件扮演的另一個角色,「用來與瀏覽器溝通的窗口」又是什麼意思呢?

瀏覽器內建的對話框

先來個最常見的例子: alert() 「警告對話框」:

https://ithelp.ithome.com.tw/upload/images/20171214/200655047beYeopUdw.png
(alert on Chrome)

我想不管是不是剛接觸 JavaScript 的朋友,對 alert 應該都不陌生,alert 的完整語法其實是這樣:

window.alert(message);

如同我們所熟知的全域變數一樣,window 物件下的成員,window 是可以省略不打的。

一行程式碼就可以生成一個對話框,很神奇吧?
而這就是瀏覽器環境的 BOM 提供給 JavaScript 控制的功能之一。

類似的對話框還有用來提供「確定/取消」的 window.confirm() window.confirm ,以及開放式問答的 window.prompt() window.prompt 對話框。

當然 BOM 提供的 API 很多,包含開啟/關閉視窗,改變視窗大小,計時器與取得網址等等。 這些在之後的文章當中還會再詳細解說。


DOM 是什麼?

DOM (Document Object Model,文件物件模型),是一個將 HTML 文件以樹狀的結構來表示的模型,而組合起來的樹狀圖,我們稱之為「DOM Tree」。

簡單來說,我們把 HTML 每個節點的關係攤來看,就好像是一棵樹一樣。
假設我們有一個基本的 HTML 如下:

<html>
  <head>
    <title>一個簡單的網頁</title>
  </head>

  <body>
    <h1>這是標題</h1>
    <p>這是一個<i>簡單</i>的網頁</p>
  </body>

</html>

https://ithelp.ithome.com.tw/upload/images/20171214/20065504rULoAa69HV.png

在最根部的地方,就是 document,就是 BOM 圖中 window 下面的那個。

往下可以延伸出一個個的 HTML 標籤,一個節點就是一個標籤,往下又可以再延伸出「文本節點」與「屬性的節點」。

而 DOM API 就是定義了讓 JavaScript 可以存取、改變 HTML 架構、樣式和內容的方法,甚至是對節點綁定的事件。

JavaScript 就是透過 DOM 提供的 API 來對 HTML 做存取與操作。


「DOM」 與「BOM」的區別

前面介紹 BOM 時,我們已經知道 DOM 的 document 其實也是 window 物件的子物件之一。

而「DOM」 與「BOM」最大的區別在於:

  • BOM: JavaScript 與「瀏覽器」溝通的窗口,不涉及網頁內容。
  • DOM: JavaScript 用來控制「網頁」的節點與內容的標準。

「BOM」完全依賴於瀏覽器廠商實作本身無標準規範,而「DOM」有著 W3C 所制定的標準來規範。


想要透過 DOM API 取得節點,透過 JavaScript 可以這樣寫:

// 根據傳入的值,找到 DOM 中 id 為 'xxx' 的元素。
document.getElementById('xxx');

// 針對給定的 tag 名稱,回傳所有符合條件的 NodeList 物件 [註1]
document.getElementsByTagName('xxx');

// 針對給定的 class 名稱,回傳所有符合條件的 NodeList 物件。
document.getElementsByClassName('xxx');

// 針對給定的 Selector 條件,回傳第一個 或 所有符合條件的 NodeList。
document.querySelector('xxx');
document.querySelectorAll('xxx');

而透過 DOM API 選取出來的節點,我們可以透過操作 textContent 屬性來變更它的文字。

假設有一個 HTML 節點:

<h1 id="greet"></h1>

再來我們就可以先透過 document.querySelector() 方法來取得節點,然後修改 textContent 屬性:

<script>
  document.querySelector('#greet').textContent = 'Hello World!'
</script>

JS Bin on jsbin.com

看到這裡,恭喜你已經可以透過 JavaScript 在網頁上輸出 "Hello World!" 囉!

在後續的內容中,我們會繼續來介紹各種操作網頁的 DOM/BOM API。
畢竟對前端工程師來說,搞懂怎麼與瀏覽器打交道、怎麼操作網頁內容,就是做好 WebUI 最重要的基礎。


  • [註1]: NodeList 物件是節點的集合,可藉由 Node.childNodes 屬性或 document.querySelectorAll() 等方法取得。 NodeList 雖然有著與陣列相似的特性,但不是陣列,所以也不會有陣列相關的 method 可以使用 (如 mapfilter 等)。

上一篇
重新認識 JavaScript: Day 10 函式 Functions 的基本概念
下一篇
重新認識 JavaScript: Day 12 透過 DOM API 查找節點
系列文
重新認識 JavaScript37

1 則留言

0
cheerfulkid74
iT邦新手 5 級 ‧ 2018-03-31 10:55:52

感謝分享,覺得這真的是個很重要的觀念!

我要留言

立即登入留言