JavaScript

JavaScript（通常縮寫為JS）是一門基於原型和頭等函數的多範式高級直譯程式語言，它支持面向對象程式設計、指令式編程和函數式編程。它提供方法來操控文本、陣列、日期以及正則表達式等。不支持I/O，比如網路、存儲和圖形等，但這些都可以由它的宿主環境提供支持。它由Ecma通過ECMAScript實現語言的標準化。目前，它被世界上的絕大多數網站所使用，也被世界主流瀏覽器（Chrome、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年12月1日正式申請註冊JavaScript的商標，於2000年7月28日獲批，但此後昇陽電腦公司和之後收購它的甲骨文公司從未使用該商標製造過產品，給JavaScript社區帶來了不確定性，阻礙了JavaScript社區的自由發展，直到幾十年後，1.5萬多名JavaScript社區成員於2024年11月22日聯名向美國專利商標局申請終止該商標，甲骨文公司於2025年2月3日以Node.js產品回復了該申請案，終止流程仍待決。

### 微軟採納

微軟公司於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具有非常豐富的特性。

在21世紀初Internet Explorer占主導地位期間，客戶端腳本停滯不前。這在2004年開始改變，當時Netscape的繼任者Mozilla發布了Firefox瀏覽器。Firefox受到許多人的好評，從Internet Explorer獲得了巨大的市場份額。

2005年，Mozilla加入了ECMA International，並開始研究ECMAScript for XML（E4X）標準。這導致Mozilla與Macromedia（後來被Adobe Systems收購）合作，他們正在用基於ECMAScript 4草案的ActionScript 3語言實現E4X。目標是將ActionScript 3標準化為新的ECMAScript 4。為此，Adobe Systems將Tamarin實現作為開源項目發布。然而，Tamarin和ActionScript 3與既定的客戶端腳本太不同，如果沒有微軟的合作，ECMAScript 4從未取得成果。

與此同時，與ECMA工作無關的開源社區正在發生非常重要的發展。2005年，傑西·詹姆士·賈瑞特(Jesse James Garrett)發布了一部落格，其中他創造了「AJAX」一詞，並描述了一套技術，其中JavaScript是骨幹，用於創建可以在後台加載數據的Web應用程式，避免了重新加載整頁的需要。這引發了JavaScript的復興時期，由開源庫和圍繞它們形成的社區帶頭。創建了許多新庫，包括jQuery、Prototype、Dojo Toolkit和MooTools。

谷歌於2008年首次推出Chrome瀏覽器，其V8 JavaScript引擎比競爭對手更快。關鍵的創新是及時編譯（JIT），因此其他瀏覽器供應商需要為JIT徹底改革他們的引擎

2008年7月，這些不同領域的相關代表在奧斯陸舉行會議。這導致在2009年初達成了最終協議，將所有相關工作結合起來，推動語言向前發展。結果是2009年12月發布的ECMAScript 5標準。

### 走向成熟

關於該語言的雄心勃勃的工作持續了數年，最終隨著 2015 年ECMAScript 6的發布而正式形成了廣泛的補充和改進。

瑞安·達爾(Ryan Dahl)在 2009 年創建的Node.js引發了網頁瀏覽器之外 JavaScript 使用的顯著增加。Node.js結合了V8引擎、事件循環和I/O API，從而提供了獨立的 JavaScript 運行時系統。截至 2018 年，Node.js 已被數百萬開發人員使用，並且npm擁有世界上所有軟體包管理系統中最多的模塊。

ECMAScript 草案規範目前在GitHub上公開維護，並通過定期的年度快照生成版本。對語言的潛在修訂通過全面的提案流程進行審查。現在，開發人員不再單獨檢查即將推出的功能的狀態，而不是版本號。

當前的 JavaScript 生態系統擁有許多庫和框架、已建立的編程實踐以及在網頁瀏覽器之外大量使用 JavaScript。另外，隨著單頁應用程式和其他大量使用 JavaScript 的網站的興起，已經創建了多個轉譯器來幫助開發過程。

## 概論

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

- ECMAScript，描述了該語言的語法和基本對象。
- 文檔對象模型（DOM），描述處理網頁內容的方法和接口。
- 瀏覽器對象模型（BOM），描述與瀏覽器進行交互的方法和接口。

JavaScript的基本特點如下：

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

JavaScript常用來完成以下任務：

- 嵌入動態文本於HTML頁面。
- 對瀏覽器事件作出響應。
- 讀寫HTML元素。
- 在數據被提交到伺服器之前驗證數據。
- 檢測訪客的瀏覽器資訊。
- 控制Cookie，包括創建和修改等。

## 特性

不同於伺服器端腳本語言（如PHP和ASP），JavaScript主要被作為客戶端腳本語言在使用者的瀏覽器上運行，不需要伺服器的支持。所以在早期程式設計師比較青睞於JavaScript以減少對伺服器的負擔，而與此同時在安全性上出現了問題。隨著伺服器變得強大，現在的程序員更喜歡運行於伺服器端的腳本以保證安全，但JavaScript仍然以其跨平台、容易上手等優勢大行其道。同時，有些特殊功能（如AJAX）必須依賴JavaScript在客戶端提供支持。隨著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受到批評的原因之一，因為隱藏轉換增加了規則的複雜度和發生錯誤的可能性。

左操作數｜操作符｜右操作數｜結果

`[]`（空陣列）｜`+`｜`[]`（空陣列）｜`""`（空字符串）

`[]`（空陣列）｜`+`｜`{}`（空對象）｜`"[object Object]"`（字串）

`false`（布爾值）｜`+`｜`""`（空字符串）｜`"false"`（字串）

`"123"`（字串）｜`+`｜`1`（數字）｜`"1231"`（字串）

`"123"`（字串）｜`-`｜`1`（數字）｜`122` （數字）

### 動態化

#### 類型

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的「承諾」（`Promise`）是一種編程模型，它允許表示可能在未來某個時間點完成或失敗的值。承諾被設計為一個解決異步編程中所遇到的問題的更簡潔和一致的方法。相比於傳統的回調函數，它為處理異步操作提供了一個更清晰的方式。

一個承諾有三種狀態：

待定（Pending）: 初始狀態，既不是成功也不是失敗。

已履行（Fulfilled）: 意味著操作成功完成。

已拒絕（Rejected）: 意味著操作失敗。

承諾的主要特點是它們的狀態一旦改變（從待定到已履行或已拒絕），就不能再次改變。這使得承諾成為一個可靠的資訊來源，無論它們是否成功。

在JavaScript中，你可以使用`then()`方法來附加回調函數，這些回調函數會在承諾達到已履行或已拒絕狀態時執行。還有一個`catch()`方法，專門用於處理被拒絕的承諾。為了使鏈式調用更簡潔，`then()`和`catch()`都會返回一個新的承諾。ES6（ECMAScript 2015）引入了原生的`Promise`對象，從此承諾成為JavaScript標準的一部分。此後的版本還提供了額外的實用方法，例如`Promise.all()`和`Promise.race()`，用於處理多個承諾。

#### 異步

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

#### 變長參數

JavaScript中函數參數的長度是可變的，在函數內部可以通過`arguments`對象訪問這些參數。

## 編程

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

```javascript
console.log("a");  //這是正確的
console.log("b");  //這是正確的
console.logg("c"); //這是錯誤的，並且到這裡會停下來
console.log("d");  //這是正確的
console.log("e");  //這是正確的

/* 解決辦法 */
try { console.log("a"); } catch (e) {}  //這是正確的
try { console.log("b"); } catch (e) {}  //這是正確的
try { console.logg("c"); } catch (e) {} //這是錯誤的，但是到這裡不會停下來，而是跳過
try { console.log("d"); } catch (e) {}  //這是正確的
try { console.log("e"); } catch (e) {}  //這是正確的
```

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

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

## 範例

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

```html5
<!DOCTYPE HTML>
<html>
    <head>
    <title>簡單的JavaScript Hello World</title>
        <script>
            document.write("Hello, world!");   // 於瀏覽器視窗內直接顯示
            alert("Hello, world!");            // 開啟對話視窗顯示
            console.log("Hello, world!");      // 於console裡顯示，需要先開啟開發工具控制台
        </script>
    </head>
    <body>
　　　　HTML內容……
    </body>
</html>
```

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

```javascript
javascript:alert("Hello world!");
```

## 版本

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

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

版本｜發布日期｜基於｜NetscapeNavigator｜MozillaFirefox｜InternetExplorer｜Opera｜Safari｜GoogleChrome

o｜1996年3月｜2.0｜3.0

o｜1996年8月｜3.0

o｜1997年6月｜4.0 - 4.05｜3

o｜1998年10月｜ECMA-262 1st + 2nd edition｜4.06 - 4.7x｜4.0｜5

o｜NetscapeServer｜6

o｜2000年11月｜ECMA-262 3rd edition｜6.0｜1.0｜5.5（JScript 5.5）6（JScript 5.6）7（JScript 5.7）8（JScript 5.8）｜7.0｜3.0-5｜1.0 - 10.0.666

o｜2005年11月｜1.5 + Array extras + Array and string generics + E4X｜1.5

o｜2006年10月｜1.6 + Pythonic generators + Iterators + Let｜2.0｜28.0.1500.95

o｜2008年6月｜1.7 + Generator expressions + Expression closures｜3.0｜11.50

o｜1.8 + native JSON support + Minor updates｜3.5

o｜2009年6月22日｜1.8.1 + Minor updates｜3.6

o｜2010年7月27日｜1.8.2 + New features for ECMA-262 5th edition compliance｜4.0

## 外部連結

- 關於JavaScript介紹 Mozilla Developer Network上的資源

## 基本資料

- 編程范型：事件驅動、函數式、指令式
- 發行時間：1995年12月4日
- screenshot caption：JavaScript原始碼截圖
- 設計者：創造者布蘭登·艾克及ECMAScript規範的其他關鍵貢獻者
- 類型系統：動態類型、鴨子類型
- 文件擴展名：`.js`、`.cjs`、`.mjs`
- 軟體實現：V8、JavaScriptCore、SpiderMonkey、Chakra
- 受影響於：AWK、C、HyperTalk、Java、Lua、Perl、Python、Scheme、Self
- 施影響於：ActionScript、AtScript、CoffeeScript、Dart、JScript .NET、LiveScript、Objective-J、Opa、QML、Raku、TypeScript
- 擴展名：.js
- mime：application/javascript、text/javascript (obsolete)
- 統一類型標識：com.netscape.javascript-source
- 類型：腳本語言