介紹 JavaScript 中的基本語法與使用方式,包含執行 JavaScript、在 HTML中 嵌入 JavaScript、註解與其他特性。

如何執行 JavaScript

JavaScript 最常使用在網頁上,所以基本上所有瀏覽器都可以用來執行 JavaScript 程式,我們簡單的建立一個網頁,例如 hello.html,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta charset="utf-8">
<title>Hello World!</title>
<script>
document.write('Hello world!');
</script>
</head>
<body>
</body>
</html>

接著利用瀏覽器開啟網頁檔,就可以看到程式的結果,document.write 表示寫入資料到文件中 (因為當前文件尚未關閉,所以會寫到文件未端,而瀏覽器會自動寫到 <body> 尾端,但如果 <body>未建立,則會在建立後跑到 <body> 的開始處),另外一種顯示方式是用 alert 函式跳出對話框,早期的 JavaScript 通常使用 alert 來顯示資料以 debug,相當不方便,現在 JavaScript 支援 console.log 的功能,能夠輸出資料到開發工具顯示。另外 HTML 的部分不在文章的範疇,所以不多作說明。

在 HTML 嵌入 JavaScript 程式

嵌入方式

直接嵌入

如前面的範例所示,在 HTML 中直接使用 <script>...</script> 的標籤來表示嵌入一段 JavaScript 程式,這裡介紹一下 <script> 標籤的屬性,早期除了 JavaScript 外其實有一些其他的 Script 語言也被使用,例如 VBSript,所以為了讓瀏覽器知道嵌入的語言是哪一種,會有以下兩種寫法:

1
2
<script language="JavaScript">
<script type="text/javascript">

其中第一種是早期非標準的方式,現在已經不建議使用,第二種方式才是有定義在標準中的方式;另外也可以直接省略屬性,直接使用 <script>,一般瀏覽器預設會使用 JavaScript,而在 HTML5 中也定義了 type 預設值為 text/javascript,所以一般而言,現在直接使用 <script> 就可以了。而嵌入的位置可以在 <head><body> 之中的任意位置 ( 不建議放在 <head> 最前面,因為 <head> 第一個節點通常為編碼宣告 )。

嵌入外部檔案

另一種方式是將 JavaScript 程式獨立寫成別的檔案,不直接和 HTML 檔案寫在一起,JavaScript 的檔案副檔名為 js,例如我們建立一個 hello.js 檔,裡面寫入:

1
document.write('Hello world!');

然後 HTML 檔案則改為:

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta charset="utf-8">
<title>Hello World!</title>
<script src="hello.js"></script>
</head>
<body>
</body>
</html>

如上所示,在 <script> 中使用 src 的屬性指出外部 js 的位址,一旦使用了這種方式,<script> 標籤中的資料會被忽略,例如:

1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta charset="utf-8">
<title>Hello World!</title>
<script src="hello.js">
alert('no alert');
</script> </head>
<body>
</body>
</html>

alert('no alert'); 不會被執行。

<noscript>

這個標籤是當使用者瀏覽器不支援或未啟用 JavaScript 時,會以文字的方式顯示標籤內的訊息。例如:

1
2
3
<noscript>
Not support
</noscript>

當瀏覽器無法執行 JavaScript 時,會看到 Not support JavaScript 而不是 Hello world!,可以利用 Firefox 的選項設定將 JavaScript 停用測試。

執行順序

瀏覽器解析網頁時,是以線性的方式處理,也就是從頭到尾一段一段解析,所以程式所在相對的順序會相當重要,以下舉幾個例子來說明:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta charset="utf-8">
<title>Hello World</title>
<script>
document.write(document.body);
</script>
</head>
<body>
</body>
</html>

document.body 表示取得 <body> 的 DOM 物件,但這例子結果會是 null。這同時也是相當多初學者會遇到的問題,這正是執行順序所造成的問題,由於在執行 JavaScript 程式時,瀏覽器尚未解析到<body> 物件,所以 <body> 尚未產生而回傳 null。同理,存取其他 DOM 物件的時候也是會有相同問題。再看下面的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta charset="utf-8">
<title>Hello World</title>
<script>
func();
func2();
function func() {
document.write('func');
}
</script>
<script>
function func2() {
document.write('func2');
}
</script>
</head>
<body>
</body>
</html>

結果 func() 順利執行,但是 func2() 會顯示尚未未定義。在 JavaScript 中以 function 敘述的方式定義會先被處理,所以即使前面呼叫後面才定義函式也是可以運作;但是由上面的例子可以發現,瀏覽器其實是以元素 (Element) 為單位來解析內容,由於 func2 是在第二個 <script> 元素中才被定義,所以第一個 <script>func2() 尚未被定義。同理,當 func2 改成定義在外部 js,也是會顯示尚未定義。

為了解決這個問題,我們通常會等待瀏覽器將整個網頁文件解析完成後再來執行程式,而如何確保文件載入完成有以下三種方法:

onload
利用 <body>onload 事件來讓文件完成載入之後觸發,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta charset="utf-8">
<title>Hello World</title>
<script>
function init() {
alert(document.body);
}
</script>
</head>
<body onload="init();">
...
</body>
</html>

建立一個函式來指派給文件載入事件後觸發。

嵌入至文件結尾處
程式碼移至程式結尾處,也就是 </body> 之前的位置,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta charset="utf-8">
<title>Hello World</title>
</head>
<body>
...
<script>
alert(document.body);
</script>
</body>
</html>

此時 <script> 之前的物件皆已經建立。

defer
利用 <script> 標籤的 defer 屬性,告知瀏覽器此段程式碼稍後執行,如下:

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta charset="utf-8">
<title>Hello World</title>
<script src="defer.js" defer="defer"></script>
</head>
<body>
</body>
</html>

雖然有些瀏覽器會讓這個屬性直接作在任何 <script>,但標準中定義這個屬性只在載入外部檔案時作用,所以還是以標準的作法為主。必須注意一點,在 defer 的 js 中使用 document.write 會有問題,所以不建議這兩個一起使用,例如在 Chrome 會無法輸出。

JavaScript 與 HTML 搭配使用

在網頁中有很多方法可以結合 JavaScript 和 HTML,讓 HTML 可以呼叫 JavaScript,這邊介紹幾種的方法:

事件屬性

如同執行順序章節出現過的 onload 就是這個方式的應用,能夠在 HTML 的元素中定義特定的事件去觸發特定的程式,不同的 HTML 元素支援不同的事件,這必須要參考標準文件。這裡以按鈕點擊事件為範例:

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta charset="utf-8">
<title>Hello World</title>
</head>
<body>
<input type="button" value="Click Me" onclick="alert('Hello');" />
</body>
</html>

超連結

另一種方式是透過超連結,利用 <a> 元素的 href 屬性來達成,以 javascript: 為開頭表示執行 JavaScript 指令,如下:

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta charset="utf-8">
<title>Hello World</title>
</head>
<body>
<a href="javascript:alert('Hello');">Click Me</a>
</body>
</html>

javascript: 是一種虛擬的 URI,這個方法也常利用來建立空連結,例如:

1
<a href="javascript:void(0);">Click Me</a>

或者也有人這樣寫

1
<a href="javascript:">Click Me</a>

該超連結就不會有作用,這種用法通常是為了某些特殊的目的,例如以超連結的樣式呈現,背後實際用JavaScript執行點擊後的事件。

透過 JavaScript 操作

另一種方式是利用 JavaScript 程式動態的為 HTML 物件加上事件,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta charset="utf-8">
<title>Hello World</title>
</head>
<body>
<a href="javascript:void(0)" id="link">Click Me</a>
<script>
var link = document.getElementById('link');
link.onclick = function() {
alert('Hello');
};
</script>
</body>
</html>

雖然這個方式看起來比較複雜,但 JavaScript 深入使用之後,這種方式反而是最常使用。

註解

註解的用法

註解的部份不會執行,是給人看的,JavaScript 中有兩種註解方式:

  1. // 單行註解:兩個斜線後面的部份將不會處理。
  2. /* ... */ 多行註解:註解中間的部份將不會處理。
1
2
3
alert("註解一"); //單行註解
alert("註解二"); /*多行註解
第二行*/

註解的技巧

我們可以利用 //* ... //*/ 的寫法來作為區塊註解的開關

1
2
3
4
5
6
7
alert("不會影響到");
//*區塊註解開關
if ($confition) {
alert("要註解的區塊");
}
//*/
alert("不會影響到");

藉由刪除 / 加入開頭的斜線作為開啟或關閉區塊

1
2
3
4
5
6
7
alert("不會影響到");
/*區塊註解開關
if ($confition) {
alert("要註解的區塊");
}
//*/
alert("不會影響到");

常見的問題

有時候程式中的字元會影響到註解,例如:

1
2
3
/*
alert('常犯的錯誤'); /* 註解的解析錯誤 */
*/
1
2
3
/*
var reg = new RegExp('/^\d.*/');
*/

分號結尾

JavaScript 如一般程式語言,每段程式結尾都是以分號表示,但 JavaScript 能夠自動幫你在未加上分號的結尾加上分號,例如:

1
2
alert('Hello')
alert('World');

第一行沒加上分號並不會造成解析錯誤,JavaScript 容許這樣的錯誤發生。然而省略分號並不是一件正確的寫作習慣,因為有時候 JavaScript 會誤解你意思而造成程式錯誤,例如:

1
2
3
4
5
6
7
var func = function () {
return 42;
} // 省略分號

(function () {
// ...
})();

原本的意思是,建立一個函式變數,接著在 Clousre 中執行部分程式,但是瀏覽器以為你是要這樣

1
2
3
4
5
6
7
var func = (function () {
return 42;
})(function () {})();

// 1. 建立函式 function () { return 42; }
// 2. 將 function () {} 作為參數代入 1 的函式執行
// 3. 將回傳的結果 42 作為函式執行

然而 42 是數字,無法執行造成錯誤。

也因為這個特性,有時候如果在不正確的地方斷行,也會造成不如預期的結果,例如:

1
2
return
true;

原本是要回傳 true,卻被當成:

1
2
return;
true;

另一個例子

1
2
break
loop;

原本是要跳出 loop 這個迴圈,卻被當成:

1
2
break;
loop;

只跳出當前的迴圈。

延伸閱讀

下一篇 JavaScript 教學 - 資料型態 (Data Type) - 上
網頁開發人員工具