JavaScript教學 - 基本語法(Syntax)
介紹JavaScript中的基本語法與使用方式,包含執行JavaScript、在HTML中嵌入JavaScript、註解與其他特性。
1. 如何執行JavaScript
JavaScript最常使用在網頁上,所以基本上所有瀏覽器都可以用來執行JavaScript程式,我們簡單的建立一個網頁,例如hello.html,如下:
<!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的部分不在文章的範疇,所以不多作說明。
2. 在HTML嵌入JavaScript程式
2.1 嵌入方式
2.1-1 直接嵌入
如前面的範例所示,在HTML中直接使用<script>...</script>的標籤來表示嵌入一段JavaScript程式,這裡介紹一下<script>標籤的屬性,早期除了JavaScript外其實有一些其他的Script語言也被使用,例如VBSript,所以為了讓瀏覽器知道嵌入的語言是哪一種,會有以下兩種寫法:
- <script language="JavaScript">
- <script type="text/javascript">
其中第一種是早期非標準的方式,現在已經不建議使用,第二種方式纔是有定義在標準中的方式;另外也可以直接省略屬性,直接使用<script>,一般瀏覽器預設會使用JavaScript,而在HTML5中也定義了type預設值為text/javascript,所以一般而言,現在直接使用<script>就可以了。而嵌入的位置可以在<head>和<body>之中的任意位置(不建議放在<head>最前面,因為<head>第一個節點通常為編碼宣告)。
2.1-2 嵌入外部檔案
另一種方式是將JavaScript程式獨立寫成別的檔案,不直接和HTML檔案寫在一起,JavaScript的檔案副檔名為js,例如我們建立一個hello.js檔,裡面寫入:
document.write('Hello world!');
然後HTML檔案則改為:
<!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>標籤中的資料會被忽略,例如:
<!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');不會被執行。
2.2 <noscript>
這個標籤是當使用者瀏覽器不支援或未啟用JavaScript時,會以文字的方式顯示標籤內的訊息。例如:
<noscript> Not support </noscript>
當瀏覽器無法執行JavaScript時,會看到Not support JavaScript而不是Hello world!,可以利用Firefox的選項設定將JavaScript停用測試。
2.3 執行順序
瀏覽器解析網頁時,是以線性的方式處理,也就是從頭到尾一段一段解析,所以程式所在相對的順序會相當重要,以下舉幾個例子來說明:
<!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物件的時候也是會有相同問題。再看下面的例子:
<!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事件來讓文件完成載入之後觸發,如下:
<!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>之前的位置,如下:
<!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屬性,告知瀏覽器此段程式碼稍後執行,如下:
<!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會無法輸出。
2.4 JavaScript與HTML搭配使用
在網頁中有很多方法可以結合JavaScript和HTML,讓HTML可以呼叫JavaScript,這邊介紹幾種的方法:
事件屬性
如同2.3節出現過的onload就是這個方式的應用,能夠在HTML的元素中定義特定的事件去觸發特定的程式,不同的HTML元素支援不同的事件,這必須要參考標準文件。這裡以按鈕點擊事件為範例:
<!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指令,如下:
<!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,這個方法也常利用來建立空連結,例如:
<a href="javascript:void(0);">Click Me</a>
或者也有人這樣寫
<a href="javascript:">Click Me</a>
該超連結就不會有作用,這種用法通常是為了某些特殊的目的,例如以超連結的樣式呈現,背後實際用JavaScript執行點擊後的事件。
透過JavaScript操作
另一種方式是利用JavaScript程式動態的為HTML物件加上事件,如下:
<!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深入使用之後,這種方式反而是最常使用。
3. 註解
3.1 註解的用法
註解的部份不會執行,是給人看的,JavaScript中有兩種註解方式:
1. // 單行註解:兩個斜線後面的部份將不會處理。
2. /* ... */ 多行註解:註解中間的部份將不會處理。
alert("註解一"); //單行註解 alert("註解二"); /*多行註解 第二行*/
3.2 註解的技巧
我們可以利用//* ... //*/的寫法來作為區塊註解的開關
alert("不會影響到"); //*區塊註解開關 if ($confition) { alert("要註解的區塊"; } //*/ alert("不會影響到");
藉由刪除/加入開頭的斜線作為開啟或關閉區塊
alert("不會影響到"); /*區塊註解開關 if ($confition) { alert("要註解的區塊"; } //*/ alert("不會影響到");
3.3 常見的問題
有時候程式中的字元會影響到註解,例如:
/* alert('常犯的錯誤'); /* 註解的解析錯誤 */ */
/* var reg = new RegExp('/^\d.*/'); */
4. 分號結尾
JavaScript如一般程式語言,每段程式結尾都是以分號表示,但JavaScript能夠自動幫你在未加上分號的結尾加上分號,例如:
alert('Hello') alert('World');
第一行沒加上分號並不會造成解析錯誤,JavaScript容許這樣的錯誤發生。然而省略分號並不是一件正確的寫作習慣,因為有時候JavaScript會誤解你意思而造成程式錯誤,例如:
var func = function() { return 42; } // 省略分號 (function() { // ... })();
原本的意思是,建立一個函式變數,接著在Clousre中執行部分程式,但是瀏覽器以為你是要這樣
var func = function() {return 42;} ( function() {} ) (); // 1 2 3 // 1. 建立函式 function() {return 42;} // 2. 將 function() {} 作為參數代入1的函式執行 // 3. 將回傳的結果(42)作為函式執行
然而42是數字,無法執行造成錯誤。
也因為這個特性,有時候如果在不正確的地方斷行,也會造成不如預期的結果,例如:
return true;
原本是要回傳true,卻被當成:
return; true;
另一個例子
break loop;
原本是要跳出loop這個迴圈,卻被當成:
break; loop;
只跳出當前的迴圈。
延伸閱讀