構建你自己的函式

在上一篇文章中處理了大部分基本理論之後,本文將提供實踐經驗。在這裡,你將獲得一些構建自己的自定義函式的實踐。在此過程中,我們還將解釋一些處理函式的有用細節。

預備知識 瞭解 HTMLCSS 基礎知識,熟悉上一課中涵蓋的 JavaScript 函式基礎。
學習成果
  • 構建自定義函式的經驗。
  • 為函式新增引數。
  • 呼叫函式。

讓我們構建一個函式

我們要構建的自定義函式將命名為 displayMessage()。它將在網頁上顯示一個自定義訊息框,並作為瀏覽器內建 alert() 函式的自定義替代品。我們之前見過這個,但讓我們重新整理一下記憶。在你的瀏覽器 JavaScript 控制檯中,在任何你喜歡的頁面上輸入以下內容:

js
alert("This is a message");

alert() 函式接受一個引數——在警報框中顯示的字串。嘗試改變字串來改變訊息。

alert() 函式是有限的:你可以修改訊息,但不能輕易修改其他任何東西,例如顏色、圖示或其他任何東西。我們將構建一個更有趣的。

注意:此示例應該在所有現代瀏覽器中正常工作,但在稍微舊的瀏覽器中樣式可能會有點奇怪。我們建議你在現代瀏覽器(如 Firefox、Opera 或 Chrome)中進行此練習。

基本函式

首先,讓我們組合一個基本函式。

注意:對於函式命名約定,你應該遵循與變數命名約定相同的規則。這很好,因為你可以區分它們——函式名後面帶有括號,而變數名沒有。

  1. 首先訪問 function-start.html 檔案並製作一個本地副本。你會看到 HTML 很簡單——只包含一個按鈕。我們還提供了一些基本的 CSS 來樣式化自定義訊息框,以及一個空的 <script> 元素來放置我們的 JavaScript。

  2. 接下來,在 <script> 元素中新增以下內容

    js
    function displayMessage() {
      // …
    }
    

    我們以關鍵字 function 開頭,這意味著我們正在定義一個函式。這後面跟著我們希望給函式起的名稱、一組括號和一組花括號。我們希望給函式的任何引數都放在括號內,而當我們呼叫函式時執行的程式碼則放在花括號內。

  3. 最後,在花括號內新增以下程式碼

    js
    const body = document.body;
    
    const panel = document.createElement("div");
    panel.setAttribute("class", "msgBox");
    body.appendChild(panel);
    
    const msg = document.createElement("p");
    msg.textContent = "This is a message box";
    panel.appendChild(msg);
    
    const closeBtn = document.createElement("button");
    closeBtn.textContent = "x";
    panel.appendChild(closeBtn);
    
    closeBtn.addEventListener("click", () =>
      panel.parentNode.removeChild(panel),
    );
    

這有很多程式碼需要理解,所以我們將逐步為你講解。

第一行使用 DOM API 獲取全域性 document 物件的 body 屬性,選擇 <body> 元素,並將其賦值給一個名為 body 的常量,以便我們以後可以使用它

js
const body = document.body;

下一節使用一個名為 document.createElement() 的 DOM API 函式來建立一個 <div> 元素,並將其引用儲存在一個名為 panel 的常量中。這個元素將是我們訊息框的外部容器。

然後,我們使用另一個名為 Element.setAttribute() 的 DOM API 函式,為我們的面板設定一個 class 屬性,值為 msgBox。這使得樣式化元素更容易——如果你檢視頁面上的 CSS,你會看到我們正在使用 .msgBox 類選擇器來樣式化訊息框及其內容。

最後,我們在之前儲存的 body 常量上呼叫一個名為 Node.appendChild() 的 DOM 函式,它將一個元素巢狀在另一個元素內部作為其子元素。我們將面板 <div> 指定為我們要追加到 <body> 元素內部的子元素。我們需要這樣做,因為我們建立的元素不會自己出現在頁面上——我們需要指定將其放在何處。

js
const panel = document.createElement("div");
panel.setAttribute("class", "msgBox");
body.appendChild(panel);

接下來的兩部分使用了我們已經見過的相同的 createElement()appendChild() 函式來建立兩個新元素——一個 <p> 和一個 <button>——並將它們作為面板 <div> 的子元素插入到頁面中。我們使用它們的 Node.textContent 屬性(它表示元素的文字內容)在段落中插入一條訊息,在按鈕中插入一個“x”。當用戶想要關閉訊息框時,這個按鈕就是需要點選/啟用的。

js
const msg = document.createElement("p");
msg.textContent = "This is a message box";
panel.appendChild(msg);

const closeBtn = document.createElement("button");
closeBtn.textContent = "x";
panel.appendChild(closeBtn);

最後,我們呼叫 addEventListener() 來新增一個函式,該函式將在使用者點選“關閉”按鈕時被呼叫。該程式碼將從頁面中刪除整個面板——以關閉訊息框。

簡而言之,addEventListener() 方法由按鈕(實際上,是頁面上的任何元素)提供,它可以傳遞一個函式和一個事件名稱。在這種情況下,事件名稱是“click”,這意味著當用戶點選按鈕時,該函式將執行。你將在我們的事件文章中學習更多關於事件的知識。函式內部的行使用 Node.removeChild() DOM API 函式來指定我們要刪除 HTML 元素的特定子元素——在這種情況下,是面板 <div>

js
closeBtn.addEventListener("click", () => panel.parentNode.removeChild(panel));

基本上,這整段程式碼正在生成一段看起來像這樣的 HTML,並將其插入到頁面中:

html
<div class="msgBox">
  <p>This is a message box</p>
  <button>x</button>
</div>

這需要處理很多程式碼——如果現在你記不住它的每個部分是如何工作的,也別太擔心!我們這裡主要關注的是函式的結構和用法,但我們想為這個例子展示一些有趣的東西。

呼叫函式

你現在已經把你的函式定義很好地寫到了 <script> 元素中,但它目前什麼也不會做。

  1. 嘗試在函式下方新增以下行來呼叫它:

    js
    displayMessage();
    

    此行呼叫函式,使其立即執行。當你儲存程式碼並在瀏覽器中重新載入時,你會看到小訊息框立即出現,只出現一次。畢竟,我們只調用它一次。

  2. 現在開啟示例頁面上的瀏覽器開發者工具,進入 JavaScript 控制檯並再次輸入該行,你會看到它再次出現!所以這很有趣——我們現在有一個可重用的函式,我們可以隨時呼叫它。

然而,我們可能希望訊息框響應使用者和系統操作而出現。在實際應用中,這樣的訊息框可能會在新資料可用、發生錯誤、使用者嘗試刪除其配置檔案(“你確定嗎?”)或使用者新增新聯絡人並操作成功完成等情況下被呼叫。

在這個演示中,我們將讓訊息框在使用者點選按鈕時出現。以下是你需要遵循的步驟:

  1. 刪除你之前新增的行(displayMessage();)。

  2. 選擇 <button> 元素並將其引用儲存在一個常量中。在函式定義上方新增以下行到你的程式碼中:

    js
    const btn = document.querySelector("button");
    
  3. 為按鈕點選建立一個事件監聽器,該監聽器會呼叫我們的函式。在 const btn = 之後新增以下行:

    js
    btn.addEventListener("click", displayMessage);
    

    與我們的 closeBtn 的點選事件處理程式類似,這裡我們是在響應按鈕點選時呼叫一些程式碼。但在這種情況下,我們不是呼叫包含某些程式碼的匿名函式,而是按名稱呼叫我們的 displayMessage() 函式。

  4. 最後,嘗試儲存並重新整理頁面——現在你應該會在點選按鈕時看到訊息框出現。

你可能想知道為什麼我們沒有在函式名稱後面加上括號。這是因為我們不想立即呼叫函式——只有在按鈕被點選後才呼叫。如果你嘗試將該行更改為:

js
btn.addEventListener("click", displayMessage());

然後儲存並重新載入,你會發現訊息框在沒有點選按鈕的情況下就出現了!在這種情況下,括號有時被稱為“函式呼叫運算子”。你只在希望函式在當前作用域中立即執行時使用它們。同樣,匿名函式內部的程式碼不會立即執行,因為它在函式作用域內。

如果你嘗試了上一個實驗,請務必在繼續之前撤消最後一次更改。

用引數改進函式

就目前而言,該函式仍然不是很實用——我們不想每次都只顯示相同的預設訊息。讓我們透過新增一些引數來改進我們的函式,從而允許我們用不同的選項呼叫它。

  1. 首先,更新函式的第一行

    js
    function displayMessage() {
    

    改為

    js
    function displayMessage(msgText, msgType) {
    

    現在當我們呼叫函式時,我們可以在括號內提供兩個變數值,以指定要在訊息框中顯示的訊息和訊息的型別。

  2. 要使用第一個引數,請更新函式中的以下行:

    js
    msg.textContent = "This is a message box";
    

    改為

    js
    msg.textContent = msgText;
    
  3. 最後但同樣重要的是,你現在需要更新你的函式呼叫,以包含一些更新後的訊息文字。更改以下行:

    js
    btn.addEventListener("click", displayMessage);
    

    到這個程式碼塊

    js
    btn.addEventListener("click", () =>
      displayMessage("Woo, this is a different message!"),
    );
    

    如果我們想在括號中為我們正在呼叫的函式指定引數,那麼我們不能直接呼叫它——我們需要將其放在一個匿名函式中,這樣它就不在立即作用域內,因此不會立即被呼叫。現在,它要等到按鈕被點選後才會被呼叫。

  4. 重新載入並再次嘗試程式碼,你會看到它仍然執行良好,只是現在你還可以更改引數中的訊息,以在框中顯示不同的訊息!

一個更復雜的引數

接下來是下一個引數。這個引數將涉及更多的工作——我們將設定它,以便根據 msgType 引數的設定,函式將顯示不同的圖示和不同的背景顏色。

  1. 首先,從 GitHub 下載本次練習所需的圖示(warningchat)。將它們儲存在與 HTML 檔案相同位置的名為 icons 的新資料夾中。

    注意: 警告和聊天圖示最初來自 iconfinder.com,由 Nazarrudin Ansyari 設計——謝謝!(實際的圖示頁面已移動或刪除。)

  2. 接下來,找到 HTML 檔案中的 CSS。我們將進行一些更改,以便為圖示騰出空間。首先,將 .msgBox 寬度從以下內容更新:

    css
    width: 200px;
    

    改為

    css
    width: 242px;
    
  3. 接下來,在 .msgBox p { } 規則中新增以下行:

    css
    padding-left: 82px;
    background-position: 25px center;
    background-repeat: no-repeat;
    
  4. 現在我們需要在 displayMessage() 函式中新增程式碼來處理圖示的顯示。在函式的右大括號 (}) 正上方新增以下程式碼塊:

    js
    if (msgType === "warning") {
      msg.style.backgroundImage = 'url("icons/warning.png")';
      panel.style.backgroundColor = "red";
    } else if (msgType === "chat") {
      msg.style.backgroundImage = 'url("icons/chat.png")';
      panel.style.backgroundColor = "aqua";
    } else {
      msg.style.paddingLeft = "20px";
    }
    

    這裡,如果 msgType 引數設定為 "warning",則顯示警告圖示並將面板的背景顏色設定為紅色。如果設定為 "chat",則顯示聊天圖示並將面板的背景顏色設定為水藍色。如果 msgType 引數根本沒有設定(或設定為不同的值),則程式碼的 else { } 部分將起作用,段落將獲得預設的內邊距,沒有圖示,也沒有設定背景面板顏色。這提供了在未提供 msgType 引數時的預設狀態,這意味著它是一個可選引數!

  5. 讓我們測試一下我們更新後的函式,嘗試將 displayMessage() 呼叫從這個

    js
    displayMessage("Woo, this is a different message!");
    

    更改為其中一個

    js
    displayMessage("Your inbox is almost full — delete some mails", "warning");
    displayMessage("Brian: Hi there, how are you today?", "chat");
    

    你可以看到我們的(現在不再那麼)小的函式變得多麼有用。

注意:如果你在讓示例工作時遇到問題,請隨時將你的程式碼與 GitHub 上的完成版本進行檢查(也可以檢視其執行情況),或向我們尋求幫助。

總結

恭喜你到達終點!本文帶領你完成了構建一個實用的自定義函式的整個過程,再稍加努力,這個函式就可以移植到實際專案中。在下一篇文章中,我們將透過解釋另一個重要的相關概念——返回值來總結函式。