JavaScript
编程范型事件驱动函数式指令式
設計者创造者布蘭登·艾克ECMAScript规范的其他关键贡献者
发行时间1995年12月4日,​25年前​(1995-12-04[1]
穩定版本
ECMAScript 2019[2]
( 2019年6月,​22個月前​(2019-06
預覽版本
ECMAScript 2020
型態系統动态类型鸭子类型
文件扩展名
主要實作產品
V8JavaScriptCoreSpiderMonkeyChakra
啟發語言
AWK[4]CHyperTalk英语HyperTalkJava[5]LuaPerlPythonSchemeSelf
影響語言
ActionScriptAtScript英语AtScriptCoffeeScriptDartJScript .NETLiveScript英语LiveScriptObjective-J英语Objective-JOpa英语Opa_(programming_language)QMLRakuTypeScript
JavaScript
Javascript icon.svg
扩展名.js
互联网媒体类型application/javascript
text/javascript (obsolete)[6]
统一类型标识com.netscape.javascript-source[7]
格式类型脚本语言

JavaScript(通常缩写为JS)是一种高级的、解释型编程语言[8]。JavaScript是一门基于原型头等函数的语言[9],是一门多范式的语言,它支持面向对象程式設計,命令式编程,以及函数式编程。它提供语法来操控文本、数组、日期以及正则表达式等,不支持I/O,比如网络、存储和图形等,但这些都可以由它的宿主环境提供支持。它已经由ECMA(欧洲电脑制造商协会)通过ECMAScript实现语言的标准化[8]。它被世界上的绝大多数网站所使用,也被世界主流浏览器ChromeIEFirefoxSafariOpera)支持。

JavaScript与Java在名字或语法上都有很多相似性,但这两门编程语言从设计之初就有很大的不同,JavaScript的语言设计主要受到了Self(一种基于原型的编程语言)和Scheme(一门函数式编程语言)的影响[9]。在语法结构上它又与C语言有很多相似(例如if条件语句、switch语句、while循环、do-while循环等)[10]

在客户端,JavaScript在传统意义上被实现为一种解释语言,但在最近,它已经可以被即时编译(JIT)执行。随着最新的HTML5CSS3语言标准的推行它还可用于游戏、桌面和移动应用程序的开发和在服务器端网络环境运行,如Node.js

历史

肇始於網景

1993年,國家超級電腦應用中心(NCSA)發表了NCSA Mosaic,這是最早流行的圖形介面網頁瀏覽器,它在全球資訊網的普及上發揮了重要作用[11]。1994年,Mosaic的主要開發人員隨即創立了Netscape公司,並雇用了許多原來的NCSA Mosaic開發者用來開發Netscape Navigator,該公司的目標是取代NCSA Mosaic成為世界第一的網頁瀏覽器。在四個月內,已經佔據了四分之三的瀏覽器市場,並成為1990年代網際網路的主要瀏覽器[12]。網景預見到網路需要變得更動態。公司的創始人馬克·安德森認為HTML需要一種膠水語言,讓網頁設計師和兼職程式設計師可以很容易地使用它來組裝圖片和外掛程式之類的元件,且程式碼可以直接編寫在網頁標記中。

1995年,網景招募了布兰登·艾克,目標是把Scheme語言嵌入到Netscape Navigator瀏覽器當中[13]。但更早之前,網景已經跟昇阳合作在Netscape Navigator中支援Java,這時網景內部產生激烈的爭論[14]。後來網景決定發明一種與Java搭配使用的輔助腳本語言並且語法上有些類似[15],這個決策導致排除了採用現有的語言,例如PerlPythonTcl或Scheme。為了在其他競爭提案中捍衛JavaScript這個想法,公司需要有一個可以運作的原型。艾克在1995年5月僅花了十天時間就把原型設計出來了。

最初命名為Mocha,1995年9月在Netscape Navigator 2.0的Beta版中改名為LiveScript,同年12月,Netscape Navigator 2.0 Beta 3中部署時被重新命名為JavaScript[1][16],當時网景公司与昇阳电脑公司组成的开发联盟为了让这门语言搭上Java这个编程语言“热词”,因此将其临时改名为JavaScript,日后这成为大众对这门语言有诸多误解的原因之一[17]

微軟採納

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

标准化

1996年11月,網景正式向ECMA(欧洲计算机制造商协会)提交語言標準。1997年6月,ECMA以JavaScript语言为基础制定了ECMAScript标准规范ECMA-262。JavaScript成為了ECMAScript最著名的實現之一[21]。除此之外,ActionScriptJScript也都是ECMAScript规范的实现语言。儘管JavaScript作為給非程式人員的腳本語言,而非作為給程式人員的程式語言來推廣和宣傳,但是JavaScript具有非常豐富的特性。

概論

一般来说,完整的JavaScript包括以下几个部分:

  • ECMAScript,描述了该语言的语法和基本对象
  • 文档对象模型(DOM),描述处理网页内容的方法和接口
  • 浏览器对象模型(BOM),描述与浏览器进行交互的方法和接口

JavaScript的基本特点如下:

  • 是一种解释性脚本语言(代码不进行预编译)。
  • 主要用来向HTML页面添加交互行为
  • 可以直接嵌入HTML页面,但写成单独的js文件有利于结构和行为的分离。

JavaScript常用来完成以下任务:

  • 嵌入动态文本于HTML页面
  • 对浏览器事件作出响应
  • 读写HTML元素
  • 在数据被提交到服务器之前验证数据
  • 检测访客的浏览器信息
  • 控制

    不同於伺服器端腳本語言,例如PHPASP,JavaScript主要被作为客户端腳本語言在用戶的瀏覽器上運行,不需要伺服器的支持。所以在早期程式設計師比較青睞於JavaScript以減少對伺服器的負擔,而與此同時也帶來另一個問題:安全性。而隨著伺服器變得強大,現在的程序員更喜歡運行於伺服器端的腳本以保證安全,但JavaScript仍然以其跨平台、容易上手等優勢大行其道。同时,有些特殊功能(如AJAX)必须依赖JavaScript在客户端进行支持。隨著引擎如V8和框架如Node.js的發展,及其事件驅動異步IO等特性,JavaScript逐漸被用來編寫伺服器端程式。且在近几年中,Node.js的出世,让JavaScript也具有了一定的服务器功能。

    以下是ECMAScript通常实现所共有的特性。

    指令式与结构化

    JavaScript从支持许多C语言的结构化编程语法(例如if条件语句、while循环、switch语句、do-while循环等)。但作用域是一个例外:JavaScript在过去只支持使用var关键字来定义变量的函数作用域。ECMAScript 2015加入了let关键字来支持块级作用域[22]。意味着JavaScript现在既支持函数作用域又支持块级作用域。和C语言一样,JavaScript中的表达式和语句是不同的。有一点格式上的不同,JavaScript支持自动在语句末添加分号,因此允许忽略语句末尾的分号。[23]

    弱类型

    Javascript是弱类型的,这意味着变量可以被隐式地转换为另一个类型。[24]

    • 二元运算符+会把两个操作数转换为字符串,除非两个操作数都为数字类型。[25]这是因为+也表示字符串连接操作。
    • 二元操作符-会把两个操作数转换为数字类型。[26]
    • 一元操作符,包括+-,都会把操作数转换为数字。

    下列为变量转换为字符串的例子:

    • 字符串类型不变。
    • 数字会转换为其字符串表示。
    • 数组的元素会转换为字符串,然后连接成通过逗号,分隔的长字符串。
    • 其它对象会转换为[object Object],其中Object中该对象的构造函数名。[27]

    类型的隐藏转换,是JavaScript受到批评的原因之一,因为其增加了规则的复杂度与发生错误的可能性。[28]

    JavaScript中诡异的隐式转换[29][30]:
    左操作数 操作符 右操作数 结果
    [](空数组) + [](空数组) ""(空数组)
    [](空数组) + {}(空对象) "[object Object]"(字符串)
    false(布尔值) + [](空字符串) "false"(字符串)
    "123"(字符串) + 1(数字) "1231"(字符串)
    "123"(字符串) - 1(数字) 122 (数字)

    动态化

    类型

    JavaScript是动态类型的,正如大部分脚本语言,其类型与值而不是与变量关联。例如变量可以为数值,随后又可被赋值为字符串。JavaScript提供了包括鸭子类型在内的方法来检测变量类型。

    运行时估值

    Javascript提供eval()函数,可以在运行时直接执行Javascript语句。[31]

    基于原型的面向对象

    在JavaScript中,对象是关联数组,通过原型(prototype,见下)进行扩充。每一个字符串键值提供对象的一个属性的名称。可以通过两种效果相同的方式进行访问:使用点号(obj.x)或使用方括号(obj['x'])。属性可以在运行时添加、重定义或删除。一个对象大多数属性(包括来自原型继承链的属性)都可以通过 for...in循环访问。[32]

    原型

    JavaScript使用原型,而许多其它面向对象语言使用类用于实现继承。有了原型,使得在JavaScript中模拟基于类的面向对象特征变成可能。[33]

    函数作为对象构造器

    函数在JavaScript中兼作为对象构造函数。在函数调用前加上new会创建一个原型的实例,并继承来自构造函数的属性和方法(包括来自Object原型)。[32]ECMAScript 5提供Object.create方法,可以显式地创建实例还不是自动从Object继承。[34]构造函数的prototype属性决定了用于新对象的内部原型。可以通过修改构造函数的原型的方法来为对象添加新的方法。也可以修改JavaScript的内部对象的原型,如ArrayObject。尽管可以这么做,但对Object原型进行修改并不是一个好的做法。因为大多数JavaScript对象都会从Object继承,且不会希望其原型做了修改。[35]

    函数作为方法

    与大多数而向对象的语言不同,在JavaScript中函数定义与方法定义没有明显的区别。唯一的区别在于调用时:当函数被作为方法调用时,函数的this会指向调用此函数的对象。[36]

    传统的类定义与使用格式

    ECMAScript ES6加入了对classextends关键字的支持,使得类的定义与继承行为更加类似于其它面向对象语言,同时也更加容易使用。[37][38]

    函数式

    在JavaScript中,函数是一等的,函数也被认为是对象。因此,函数也可以有属性与方法,例如call()bind等。[39]嵌套函数指定义于其它函数内部的函数,在外部函数被调用时,嵌套函数会被创建。另外,嵌套函数是一个闭包,在外部函数的作用域(包括常量,局部变量和参数)都成为内部函数状态的一部分,甚至在外部函数执行完毕后,内部函数的状态依然保留。[40]JavaScript同时也支持匿名函数[41]

    其它

    运行时环境

    JavaScript通常依赖于运行时环境(例如浏览器)来提供对象和方法,脚本可以通过这些对象和方法与环境(例如网页DOM)进行交互。它还依赖于运行时环境来提供包含/导入脚本(例如HTML<script>元素)的功能。这本身不是语言功能,但是在大多数JavaScript实现中很常见。

    异步

    JavaScript一般来说是单线程的。[42]为了并发地处理事件,JavaScript程序输入/输出是使用事件回调函数执行的。例如,这意味着JavaScript可以在等待数据库查询返回信息时处理鼠标单击。ECMAScript ES6引入了Promise用于优雅地处理异步事件,其可以使得传统的基于回调的异步代码更加清晰与简单。[43][44]

    变长参数

    JavaScript中函数的参数长度是可变的,在函数内部可以通过arguments对象访问这些参数。[45]

    编程

    JavaScript是一種腳本語言,其原始碼在發往客户端執行之前不需經過編譯,而是將文本格式的字符代碼發送給瀏覽器由瀏覽器解釋執行。直譯語言的弱點是安全性較差,而且在JavaScript中,如果一條執行不了,那麼下面的語言也無法執行。而其解決辦法就是於使用异常处理try{}catch(){}

    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

    <!DOCTYPE HTML>
    <html>
        <head>
        <title>简单的JavaScript Hello World</title>
            <script type="text/javascript">
                document.write("Hello, world!");   // 直接插入页面中
                alert("Hello, world!");            // 弹窗显示
                console.log("Hello, world!");      // 在控制台(console)里显示,需要先开启开发工具控制台
            </script>
        </head>
        <body>
        HTML内容……
        </body>
    </html>
    

    或是在瀏覽器地址栏中使用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)。

    下列表格的資訊基於多個參考來源[46][47][48][49]

    版本 發布日期 基於 Netscape
    Navigator
    Mozilla
    Firefox
    Internet
    Explorer
    Opera Safari Google
    Chrome
    舊版本,不再支援: 1.0 1996年3月 2.0 3.0
    舊版本,不再支援: 1.1 1996年8月 3.0
    舊版本,不再支援: 1.2 1997年6月 4.0 - 4.05 3
    舊版本,不再支援: 1.3 1998年10月 ECMA-262 1st + 2nd edition 4.06 - 4.7x 4.0 5[50]
    舊版本,不再支援: 1.4 Netscape
    Server
    6
    舊版本,不再支援: 1.5 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
    舊版本,不再支援: 1.6 2005年11月 1.5 + Array extras + Array and string generics + E4X 1.5
    舊版本,不再支援: 1.7 2006年10月 1.6 + Pythonic generators页面存档备份,存于互联网档案馆) + Iterators + Let 2.0 28.0.1500.95
    舊版本,不再支援: 1.8 2008年6月 1.7 + Generator expressions + Expression closures 3.0 11.50
    舊版本,不再支援: 1.8.1 1.8 + native JSON support + Minor updates 3.5
    舊版本,不再支援: 1.8.2 2009年6月22日 1.8.1 + Minor updates 3.6
    舊版本,不再支援: 1.8.5 2010年7月27日 1.8.2 + New features for ECMA-262 5th edition compliance 4.0

    參見