JavaScript編程語言

**JavaScript**（通常縮寫為 **JS**）是一門基於原型和頭等函式的多範式進階直譯程式語言，它支援物件導向程式設計、指令式編程和函式語言程式設計。它提供方法來操控文字、陣列、日期以及正規表示式等。不支援 I/O，比如網路、儲存和圖形等，但這些都可以由它的宿主環境提供支援。它由 ECMA（歐洲電腦製造商協會）透過 ECMAScript 實作語言的標準化。目前，它被世界上的絕大多數網站所使用，也被世界主流瀏覽器（Chrome、IE、Firefox、Safari 和 Opera）所支援。

JavaScript 與 Java 在名字和語法上都很相似，但這兩門程式語言從設計之初就有很大不同。JavaScript 在語言設計上主要受到了 Self（一種原型程式設計語言）和 Scheme（一門函式語言程式設計語言）的影響，在語法結構上它和 C 語言很相似（如 if 條件語句、switch 語句、while 迴圈和 do-while 迴圈等）。

對於客戶端來說，JavaScript 通常被實作為一門解釋語言，但如今它已經可以被即時編譯（JIT）。隨著 HTML5 和 CSS3 語言標準的推行，它還可以用於遊戲、桌面和行動應用程式的開發，以及在伺服器端網路環境執行（如 Node.js）。

## 歷史

### 肇始於網景

1993 年，國家超級電腦應用中心（NCSA）發表了 NCSA Mosaic，這是最早流行的圖形介面網頁瀏覽器，它在全球資訊網的普及上發揮了重要作用。1994 年，Mosaic 的主要開發人員創立了 Netscape 公司，並雇用了許多原來的 NCSA Mosaic 開發者用來開發 Netscape Navigator，該公司的目標是取代 NCSA Mosaic 成為世界第一的網頁瀏覽器。在四個月內，已經佔據了四分之三的瀏覽器市場，並成為 1990 年代網際網路的主要瀏覽器。

在網路發展的這些年，網頁只能是靜態的，缺乏在瀏覽器中載入網頁後的動態行為能力。公司的創始人馬克・安德森認為 HTML 需要一種膠水語言，讓網頁設計師和兼職程式設計師可以很容易地使用它來組裝圖片和外掛程式之類的元件，且程式碼可以直接編寫在網頁標記中。1995 年，網景招募了布蘭登・艾克，目標是把 Scheme 語言嵌入到 Netscape Navigator 瀏覽器中。但更早之前，網景已經跟昇陽合作，計劃在 Netscape Navigator 中嵌入 Java 語言，這時網景內部產生激烈的爭論，

網景公司管理層很快決定，最佳的方案是由艾克設計一種新的語言，其語法類似於 Java，而不像 Scheme 或其他現存的腳本語言。為了在其他競爭提案中捍衛 JavaScript 這個想法，公司需要有一個可以運作的原型。艾克在 1995 年 5 月僅花了十天時間就把原型設計出來了。最初命名為 **Mocha**，1995 年 9 月在 Netscape Navigator 2.0 的 Beta 版中改名為 **LiveScript**，同年 12 月，Netscape Navigator 2.0 Beta 3 中部署時被重新命名為 **JavaScript**。當時網景公司與昇陽電腦公司組成的開發聯盟為了讓這門語言搭上 Java 這個程式語言「熱詞」，因此將其臨時改名為 JavaScript，日後這成為大眾對這門語言有諸多誤解的原因之一。

### 微軟採納

微軟公司於 1995 年首次推出 Internet Explorer，引發了與 Netscape 的瀏覽器大戰。微軟對 Netscape Navigator 直譯器進行了逆向工程，建立了 JScript，以與處於市場領導地位的網景產品同台競爭。JScript 也是一種 JavaScript 實作，這兩個 JavaScript 語言版本在瀏覽器端共存意味著語言標準化的缺失。發展初期，JavaScript 的標準並未確定，同期就有網景的 JavaScript 和微軟的 JScript。除此之外，微軟也在網頁技術上加入了不少專屬物件，使不少網頁使用非微軟平台及瀏覽器無法正常顯示。這導致在瀏覽器大戰期間網頁設計者通常會把「用 Netscape 可達到最佳效果」或「用 IE 可達到最佳效果」的標誌放在首頁。

### 標準化

1996 年 11 月，網景正式向 ECMA（歐洲電腦製造商協會）提交語言標準。1997 年 6 月，ECMA 以 JavaScript 語言為基礎制定了 ECMAScript 標準規範 ECMA-262。JavaScript 成為了 ECMAScript 最著名的實現之一。除此之外，ActionScript 和 JScript 也都是 ECMAScript 規範的實作語言。儘管 JavaScript 作為給非程式人員的腳本語言，而非作為給程式人員的程式語言來推廣和宣傳，但是 JavaScript 具有非常豐富的特性。

## 概論

一般來說，完整的 JavaScript 包括以下幾個部分：

* ECMAScript，描述了該語言的語法和基本物件；
* 文件物件模型（DOM），描述處理網頁內容的方法和介面；
* 瀏覽器物件模型（BOM），描述與瀏覽器進行互動的方法和介面。

JavaScript 的基本特點如下：

* 是一種解釋性腳本語言（代碼不進行預編譯）；
* 主要用來向 HTML 頁面添加互動行為；
* 可以直接嵌入 HTML 頁面，但寫成單獨的 js 檔案有利於結構和行為的分離。

JavaScript 常用來完成以下任務：

* 嵌入動態文字於 HTML 頁面；
* 對瀏覽器事件作出回應；
* 讀寫 HTML 元素；
* 在資料被提交到伺服器之前驗證資料；
* 檢測訪客的瀏覽器資訊；
* 控制 Cookie，包括建立和修改等；

## 特性

不同於伺服器端腳本語言（如 PHP 和 ASP），JavaScript 主要被作為客戶端腳本語言在使用者的瀏覽器上運行，不需要伺服器的支援。所以在早期程式設計師比較青睞於 JavaScript 以減少對伺服器的負擔，而與此同時在安全性上出現了問題。隨著伺服器變得強大，現在的程式員更喜歡運行於伺服器端的指令碼以保證安全，但 JavaScript 仍然以其跨平台、容易上手等優勢大行其道。同時，有些特殊功能（如 AJAX）必須依賴 JavaScript 在客戶端提供支援。隨著引擎（如 V8）和框架（如 Node.js）的發展，以及事件驅動和異步 IO 等特性，JavaScript 也被逐漸用來編寫伺服器端程式。

以下是 ECMAScript 通常所實作的特性。

### 指令式與結構化

JavaScript 支援許多 C 語言的結構化編程語法（如 if 條件語句、while 迴圈、switch 語句和 do-while 迴圈等），但作用域是一個例外。JavaScript 在過去只支援使用 `var` 關鍵字來定義變數的函式作用域，但 ECMAScript 2015 中加入了 `let` 關鍵字來支援塊級作用域。這意味著 JavaScript 現在既支援函式作用域又支援塊級作用域。JavaScript 還支援自動在語句末添加分號，允許忽略語句末尾的分號。

### 弱型別

Javascript 是弱型別的，這意味著變數可以被隱式轉換為另一個類型。

* 二元運算子 `+` 會把兩個運算元轉換為字串，除非兩個運算元都為數字類型。這是因為 `+` 也表示字串連接操作；
* 二元運算子 `-` 會把兩個運算元轉換為數字類型；
* 一元運算子，包括 `+` 和 `-`，都會把運算元轉換為數字。

下列為變數轉換為字串的例子：

* 字串類型不變；
* 數字會轉換為其字串表示；
* 陣列的元素會轉換為字串，然後連接成透過逗號 `,` 分隔的長字串；
* 其它物件會轉換為 `[object Object]`，其中 `Object` 中該物件的建構函式名。

類型的隱藏轉換是 JavaScript 受到批評的原因之一，因為隱藏轉換增加了規則的複雜度和發生錯誤的可能性。

### 動態化

#### 類型

JavaScript 是動態型別的語言，其類型與值而不是與變數相關聯。例如變數可以為數字，隨後又可被賦值為字串。JavaScript 提供了包括鴨子型別在內的方法來檢測變數類型。

#### 執行時估值

Javascript 提供 `eval()` 函式，可以在執行時直接執行 Javascript 語句。

### 基於原型的物件導向

在 JavaScript 中，物件是關聯陣列，透過原型（`prototype`，見下）進行擴充。每一個字串鍵值提供物件的一個屬性的名稱，可以透過使用點號（`obj.x`）或使用方括號（`obj['x']`）這兩種效果相同的方式來存取。屬性可以在執行時添加、重定義或刪除。一個物件的大多數屬性（包括來自原型繼承鏈的屬性）都可以透過 `for...in` 迴圈存取。

#### 原型

JavaScript 使用原型，而許多其它物件導向語言使用類用於實作繼承。原型使得在 JavaScript 中類比類別為基的物件導向特徵變成可能。

#### 函式作為物件構造器

函式在 JavaScript 中兼作為物件建構函式。在函式呼叫前加上 `new` 會建立一個原型的實例，並繼承來自建構函式的屬性和方法（包括來自 `Object` 原型）。ECMAScript 5 提供 `Object.create` 方法，可以顯式地建立實例而不是自動從 `Object` 繼承。建構函式的 `prototype` 屬性決定了用於新物件的內部原型。可以透過修改建構函式的原型的方法來為物件添加新的方法，也可以修改 JavaScript 的內部物件的原型（如 `Array` 或 `Object`）。儘管可以這麼做，但對 `Object` 原型進行修改並不是好的做法。因為大多數 JavaScript 物件都會從 `Object` 繼承，且不會希望其原型被修改。

#### 函式作為方法

和大多數物件導向的語言不同，在 JavaScript 中函式定義和方法定義沒有明顯區別。唯一的區別在於呼叫時：當函式被作為方法呼叫時，函式的 `this` 會指向呼叫此函式的物件。

#### 傳統的類別定義與使用格式

ECMAScript 2015 中加入了對 `class` 和 `extends` 關鍵字的支援，使得類的定義與繼承更類似於其他的物件導向語言，同時也更易使用。

### 函數式

在 JavaScript 中，函式是一等的，函式也被認為是物件。因此，函式可以有屬性和方法，例如 `call()` 和 `bind` 等。巢狀函式指定義於其它函式內部的函式，在外部函式被呼叫時，巢狀函式會被建立。另外，巢狀函式是一個閉包，在外部函式的作用域（包括常數，局部變數和參數）都成為內部函式狀態的一部分，甚至在外部函式執行完畢後，內部函式的狀態依然保留。JavaScript 同時也支援匿名函式。

### 其它

#### 執行時環境

JavaScript 通常依賴於執行時環境（例如瀏覽器）來提供物件和方法，指令碼可以透過這些物件和方法與環境（例如網頁 DOM）進行互動。它還依賴於執行時環境來提供包或匯入指令碼（例如 HTML 的 `<script>` 元素）的功能。這本身不是語言功能，但在大多數 JavaScript 實作中很常見。

#### 非同步

JavaScript 一般來說是單執行緒的。為了並行地處理事件，JavaScript 程式輸入或輸出時使用事件和回呼函式執行。這意味著 JavaScript 可以在等待資料庫查詢返回資訊之前處理滑鼠單擊。ECMAScript 2015 引入了 `Promise` 用於處理非同步事件，其可以使得傳統的基於回呼的非同步代碼更加清晰簡單。

#### 變長參數

JavaScript 中函式參數的長度是可變的，在函式內部可以透過 `arguments` 物件存取這些參數。

## 編程

JavaScript 是一門腳本語言，其原始碼在客戶端執行前不需經過編譯，而是將文字格式的字元代碼發送給瀏覽器，由瀏覽器解釋執行。直譯語言的弱點是安全性較差，而且在 JavaScript 中，如果一條語句執行不了，通常它下面的語言也就無法執行。解決辦法是使用例外處理 `try {} catch () {}`︰

JavaScript 被歸類為直譯語言，因為主流的引擎都是每次執行時載入程式碼並解譯。V8 是將所有程式碼解譯後再開始執行，其他引擎則是逐行解譯（SpiderMonkey 會將解譯過的指令暫存，以提高效能，稱為即時編譯）。但由於 V8 的核心部份多數用 JavaScript 撰寫（而 SpiderMonkey 是用 C++），因此在不同的測試上，兩者效能互有優劣。

與其相對應的是編譯語言（如 C 語言），以編譯語言編寫的程式在執行之前必須經過編譯，將程式碼編譯為機器碼，才可以執行。

## 範例

以下是一個簡單的 JavaScript Hello World︰

或是在瀏覽器的網址列中使用 `javascript:`，以互動方式表示：

## 版本

JavaScript 最初開發於 1996 年，被使用於 Netscape Navigator 網頁瀏覽器。同年微軟在 Internet Explorer 發布了一個實作。由於商標問題，這項實作被命名為 JScript。1997 年，JavaScript 已經被網景公司提交給 ECMA 制定為標準，稱之為 ECMAScript，標準編號 ECMA-262。使用顯式版本號聲明對語言的參照，作爲一項 Mozilla 的特性，已在較新版本中被移除（至少為 Firefox 59）。Firefox 4 是最後一個需要顯式地在參照時聲明明確版本號的版本（1.8.5）。

下列表格的資訊基於多個參考來源：

## 參見

* 腳本語言
* DMDScript
* ECMAScript
* JavaScript 引擎
* JScript
* AJAX
* JavaScript 函式庫

## 參考文獻

## 外部連結

* 關於 JavaScript 介紹（頁面存檔備份，存於網際網路檔案館） Mozilla Developer Network 上的資源