JavaScript 學習指南(二)- 從網頁初心者到開發者的必經之路

上一篇我們簡單地說明了 JavaScript 的用途,以及為什麼他現在這麼受歡迎,接下來,這篇就要針對初學者在學習的過程中,比較容易困惑的核心基礎概念做更詳細的介紹。

相信大家在初學 Javascript 的時候,都一定會看到一句話:JavaScript 是一個物件導向、事件驅動(event-driven)的語言,而我們該如何詮釋 JavaScript 中的這段話呢?

JavaScript 的物件導向

物件可以說是現今學習程式語言中最重要的概念之一,你可以想像他是一個基於共同規範、功能所產生的模組化產物,舉例來說,當你走進大賣場時,你所看到的所有物品都是物件,而這些物件彼此之間可能會共享類似的功能性或是特徵,例如有蔬菜、水果、衛生紙、洗衣機、泡麵不同的分類;在其他的程式語言中,我們叫這種分類「類別(Class)」,但在 JavaScript 的世界中,我們稱呼他為原型(Prototype)。

JavaScript 是個以物件為基礎,但非標準物件導向的語言,他具備物件導向的性質,但與其他物件導向語言不同的是,他並不以類別為基礎,而是以原型(Prototype)為基礎,那原型和類別有什麼不一樣呢?

首先,我們要釐清一個概念,在 JavaScript 的世界中,所有東西都是物件,就連函式(Function)也一樣。而在 JavaScript 中,當我們要建立一些共享相同特性的物件時,我們會使用建構子(Constructor)這種函式來建立新的物件,而在建構子中有一種方法叫做原型(Prototype),這個原型方法就是讓我們可以來規範每個物件的內容屬性,並且讓後來所新創的物件都繼承(inherit)了相似的性質。

至此,JavaScript 實現了將函式作為物件看待的概念,透過 Prototype 讓 JavaScript 享有和其他物件導向程式語言相似的類別特性。 實例如下:

function myFriends(name, age, school) { this.name = name; this.age = age; this.school = school; }

來看這段程式碼,最上面 function myFriends(name, age, school) 就是建構子,代表如果我們要產生一個新的 myFriends 物件,需要傳入哪幾個參數;而下面 this. 所帶的,就是指組成這個建構子的原型屬性,例如朋友的名字、年齡和就讀學校。(關於 JavaScript 的 this 方法,你可以參考這裡的說明)

因此我們可以根據上面這個建構子,創造出幾個新的 myFriends 物件如下:

var Conan = new myFriends("柯南", 10, "帝丹小學"); var Nobita = new myFriends("大雄", 8, "下町小學");

(如果你想知道其他語言是怎麼做的,或者你想更深入了解原型繼承的概念,可以參考這篇文章。)

JavaScript 的事件驅動

事件是當我們在撰寫 JavaScript 時 非常重要的一個概念,在 JavaScript 中,事件也一樣是一個物件,有著自己的屬性。我們通常利用事件來處理流程管制,由於 JavaScript是一個單一執行緒的語言,亦即在載入時,每一段時間內只能處理一件事情(一段程式碼、一個函式),像是即使只讓一個人來負責多項工作,但這個人每次只能都專心處理所有工作的其中一部分。

這個時候我們就需要引入「事件」的概念,幫助我們實現在這種單一執行緒的模式中,還能夠對專案中的每一項任務有效率的操作;就像是你雖然是很有能力的員工,但為了控管你的時間與精力,你決定只在有需要的時候才貢獻你的才能。

那,什麼樣的東西可以被稱作一個「事件」呢?我們在上一篇文章中有提到,可以透過 JavaScript 增進使用者的互動,而這些小小的互動就可以稱作為事件。通常, JavaScript 的事件會與使用者的某種操作有關,例如:點擊按鈕、將鼠標移到某個物件、送出表單等等的動作,而一旦這些事件被觸發,就會啟動相對應的處理流程,這就是事件驅動的概念。

但對於某一些較為複雜的任務,如果每個函式所耗費的時間不同,或者是需要設定等待時間,單純透過事件來操作工作流程,可能無法滿足我們的需求,這時我們就要利用 Callback 函式來幫助我們。

JavaScript 的回呼(Callback)

如同先前所說,Callback 函式也是一個物件,而在 JavaScript 中,會大量仰賴 Callback 函式來進行事件處理。Callback 函式在一開始會被當作參數傳入一個函式之中,並在事件發生時才會被呼叫,這種函式在利用 JavaScript 時非常重要,而如果你有意往目前最夯的 Node.js 前進,更應該深入了解這個概念,因為在 Node.js 中更是大量仰賴 Callback。

到這裡你可能已經開始有點眼花,說了這麼多感覺還是很虛幻,到底實際上該如何實現呢?

這是一段簡單監控使用者點擊的程式碼,我連同上面所提到的幾段程式碼,一起放入我們在上一篇所做好的簡單版 Landing Page,再做一點小調整,我們就得到了一個充滿陽春復古風格的個人網頁,就像這樣:(請按 result 看示範效果)

(是不是讓你勾起了一點童年的回憶呢?)

document.getElementById("eventdemo").addEventListener("click", Callback); function Callback() { document.getElementById("eventdemo").innerHTML = "謝謝你~我也會去幫你回灌唷~"; };

在第一行,我們針對標有 "eventdemo" 這個 ID 的元素追蹤,也就是網頁上的這個「灌水」按鈕,並監聽使用者點擊(Click)的事件。

在第一行的後段,我們使用了一個 Callback 回呼函式,當這個事件發生時,就會回去呼叫這個函式並執行,最後你會發現,點擊後,按鈕上顯示的文字被改變了。

以 Google Analytics 的追蹤碼為例說明

大家都知道, GA 是目前追蹤網頁成效最被廣泛使用的工具之一,他可以幫助行銷人員追蹤網站的點擊率、跳出率、各個按鈕的點擊次數等等,你曾經想過他是怎麼做到的嗎?(即使是超復古風的簡單網頁,也一樣可以監控成效唷!)

是的,基本上,他就是應用到了 JavaScript 的這三個特色。

廢話不多說,直接來看看實例吧,以下這是一段 Google Analytics 的標準追蹤碼:

(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-XXXXX-Y', 'auto'); ga('send', 'pageview');

接著,讓我們來應用上面這三個特質對這段 GA 的程式碼進行簡單的分析。

首先在 function() 這個函式物件中,我們透過傳入分別代表 (i,s,o,g,r,a,m) 的參數值 (window,document,'script','https://www.google-analytics.com/analytics.js','ga'),定義出一個 ga() 的函式物件,至於中間這個看起來很複雜的東西則是這個名為 ga() 的建構式內涵,能夠幫助我們牽起和 Analytics.js 這個函式庫的溝通管道。

為什麼需要這麼做呢?因為在 Analytics.js 這個函式庫中,Google 已經幫我們做好可以運用的各種追蹤方法,例如,Create、Send、Set 等等,而我們只需要利用 function(i,s,o,g,r,a,m) 將這個溝通管道創造出來。(如果你想更了解 i,s,o,g,r,a,m 每個參數分別代表什麼意思,可以回去看看官方說明,而如果你想更了解 Analytics.js 中提供了哪些方法,則可以參考這篇說明。)

接下來,我們就可以透過 ga() 來操作 Analytics.js 函式庫中已經寫好的方法,例如使用 Create 方法,根據你的使用者 ID UA-XXXXX-Y 創造出一個追蹤器物件,並自動使用預設命名。

在下一行程式碼,我們一樣呼叫 ga(),並利用裡面的 send 方法,傳送 pageview 給我們在上一行創造出的追蹤物件,在這裡我們套入了事件的概念,而這個事件就是使用者的瀏覽量,它會在用戶點擊進入網頁,或重新刷新網頁時被計入。而這個追蹤物件會在一個瀏覽次被完成時,傳送一個瀏覽量給 Google Analytics ,這樣就完成追蹤瀏覽率的程序了,你將可以在你的 GA 帳戶後台看到結果。

在這裡我們先做個小結:在這一段程式碼中總共有四個物件,其中兩個是第一段程式碼內含的兩個函式,另外是第一段程式碼所產生出的 ga() 函式,以及透過 ga() 的create 方法所產生的追蹤器。

而在追蹤瀏覽率的時候,如果你希望在確認使用者點擊完成(例如:成功到達下一個頁面)後再記錄瀏覽(pageview),可以使用 hitCallback 這個 Callback 函式進行紀錄,因此我們可以將 ga(‘send’ )這段程式碼改寫成這樣:

ga('send', 'pageview', { 'hitCallback': function() { alert('hit sent'); } });

上面這段程式碼展示了在點擊傳送完畢後,呼叫 hitCallback 函式,最後跳出提醒(alert)告知點擊已傳送。

什麼時候會使用 hitCallback 呢?通常會在對網頁 debug 的時候使用,透過這個函式,我們可以方便地確認網站上的表單、連結是否可以正常傳送資料,同時,也可以讓我們了解事件和回呼如何進行協作。

這次我們就先說到這裡,如果針對以上概念有甚麼問題或是有希望再多介紹的概念,歡迎在下面留言交流,下一篇,我們還會再繼續針對 JavaScirpt 幾個稍微有點難度的概念作介紹,下回見囉!