编程范型 | 事件驱动、函数式、指令式 |
---|---|
設計者 | 创造者布蘭登·艾克及ECMAScript规范的其他关键贡献者 |
发行时间 | 1995年12月4日[1] |
当前版本 | |
型態系統 | 动态类型、鸭子类型 |
文件扩展名 |
|
網站 | www |
主要實作產品 | |
V8、JavaScriptCore、SpiderMonkey、Chakra | |
啟發語言 | |
AWK[5]、C、HyperTalk、Java[6]、Lua、Perl、Python、Scheme、Self | |
影響語言 | |
ActionScript、AtScript、CoffeeScript、Dart、JScript .NET、LiveScript、Objective-J、Opa、QML、Raku、TypeScript | |
|
扩展名 |
.js |
---|---|
互联网媒体类型 |
application/javascript text/javascript (obsolete)[7] |
统一类型标识 | com.netscape.javascript-source[8] |
格式类型 | 脚本语言 |
JavaScript(通常缩写为JS)是一门基于原型和头等函数的多范式高级解释型编程语言[9][10],它支持面向对象程式設計、指令式编程和函数式编程。它提供方法来操控文本、数组、日期以及正则表达式等。不支持I/O,比如网络、存储和图形等,但这些都可以由它的宿主环境提供支持。它由Ecma通过ECMAScript实现语言的标准化[9]。目前,它被世界上的绝大多数网站所使用,也被世界主流浏览器(Chrome、Firefox、Safari和Opera)所支持。
JavaScript与Java在名字和语法上都很相似,但这两门编程语言从设计之初就有很大不同。JavaScript在语言设计上主要受到了Self(一种基于原型的编程语言)和Scheme(一门函数式编程语言)的影响[10],在语法结构上它和C语言很相似(如if条件语句、switch语句、while循环和do-while循环等)[11]。
对于客户端来说,JavaScript通常被实现为一门解释语言,但如今它已经可以被即时编译(JIT)。随着HTML5和CSS3语言标准的推行,它还可以用于游戏、桌面和移动应用程序的开发,以及在服务器端网络环境运行(如Node.js)。
1993年,國家超級電腦應用中心(NCSA)發表了NCSA Mosaic,這是最早流行的圖形介面網頁瀏覽器,它在全球資訊網的普及上發揮了重要作用[12]。1994年,Mosaic的主要開發人員創立了Netscape公司,並雇用了許多原來的NCSA Mosaic開發者用來開發Netscape Navigator,該公司的目標是取代NCSA Mosaic成為世界第一的網頁瀏覽器。在四個月內,已經佔據了四分之三的瀏覽器市場,並成為1990年代網際網路的主要瀏覽器[13]。
在網路發展的這些年,網頁只能是靜態的,缺乏在瀏覽器中載入網頁後的動態行為能力。公司的創始人馬克·安德森認為HTML需要一種膠水語言,讓網頁設計師和兼職程式設計師可以很容易地使用它來組裝圖片和外掛程式之類的元件,且程式碼可以直接編寫在網頁標記中。1995年,網景招募了布兰登·艾克,目標是把Scheme語言嵌入到Netscape Navigator瀏覽器中[14]。但更早之前,網景已經跟昇阳合作,计划在Netscape Navigator中嵌入Java語言,這時網景內部產生激烈的爭論[15],
網景公司管理層很快決定,最佳的方案是由艾克設計一種新的語言,其語法類似於Java,而不像Scheme或其他現存的腳本語言。為了在其他競爭提案中捍衛JavaScript這個想法,公司需要有一個可以運作的原型。艾克在1995年5月僅花了十天時間就把原型設計出來了[16][17]。最初命名為Mocha,1995年9月在Netscape Navigator 2.0的Beta版中改名為LiveScript,同年12月,Netscape Navigator 2.0 Beta 3中部署時被重新命名為JavaScript[1][18]。當時网景公司与昇阳电脑公司组成的开发联盟为了让这门语言搭上Java这个编程语言“热词”,因此将其临时改名为JavaScript,日后这成为大众对这门语言有诸多误解的原因之一[19]。
微軟公司於1995年首次推出Internet Explorer,引發了與Netscape的瀏覽器大戰。微软對Netscape Navigator直譯器進行了逆向工程,創建了JScript,以與處於市場領導地位的網景產品同台競爭。JScript也是一種JavaScript實作,這兩個JavaScript語言版本在瀏覽器端共存意味著語言標準化的缺失。发展初期,JavaScript的标准并未确定,同期就有网景的JavaScript和微软的JScript。除此之外,微軟也在網頁技術上加入了不少專屬物件,使不少網頁使用非微軟平台及瀏覽器無法正常顯示[20][21]。这導致在瀏覽器大戰期間網頁設計者通常會把「用Netscape可達到最佳效果」或「用IE可達到最佳效果」的標誌放在首頁[20][22]。
1996年11月,網景正式向ECMA(欧洲计算机制造商协会)提交語言標準。1997年6月,ECMA以JavaScript语言为基础制定了ECMAScript标准规范ECMA-262。JavaScript成為了ECMAScript最著名的實現之一[23]。除此之外,ActionScript和JScript也都是ECMAScript规范的实现语言。儘管JavaScript作為給非程式人員的腳本語言,而非作為給程式人員的程式語言來推廣和宣傳,但是JavaScript具有非常豐富的特性。
在21世纪初Internet Explorer占主导地位期间,客户端脚本停滞不前。这在2004年开始改变,当时Netscape的继任者Mozilla发布了Firefox浏览器。Firefox受到许多人的好评,从Internet Explorer获得了巨大的市场份额。[24]
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引擎比竞争对手更快。[25]关键的创新是及时编译(JIT)[26],因此其他浏览器供应商需要为JIT彻底改革他们的引擎[27]
2008年7月,这些不同的政党聚集在一起,在奥斯陆举行会议。这导致在2009年初达成了最终协议,将所有相关工作结合起来,推动语言向前发展。结果是2009年12月发布的ECMAScript 5标准。
关于该语言的雄心勃勃的工作持续了数年,最终随着 2015 年ECMAScript 6的发布而正式形成了广泛的补充和改进。
Ryan Dahl在 2009 年创建的Node.js引发了 Web 浏览器之外 JavaScript 使用的显着增加。Node 结合了V8引擎、事件循环和I/O API,从而提供了独立的 JavaScript 运行时系统。截至 2018 年,Node 已被数百万开发人员使用,并且npm拥有世界上所有包管理器中最多的模块。
ECMAScript 草案规范目前在GitHub上公开维护,并通过定期的年度快照生成版本。对语言的潜在修订通过全面的提案流程进行审查。现在,开发人员不再单独检查即将推出的功能的状态,而不是版本号。
当前的 JavaScript 生态系统拥有许多库和框架、已建立的编程实践以及在 Web 浏览器之外大量使用 JavaScript。另外,随着单页应用程序和其他大量使用 JavaScript 的网站的兴起,已经创建了多个转译器来帮助开发过程。
一般来说,完整的JavaScript包括以下几个部分:
JavaScript的基本特点如下:
JavaScript常用来完成以下任务:
不同於伺服器端腳本語言(如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
关键字来支持块级作用域[28]。这意味着JavaScript现在既支持函数作用域又支持块级作用域。JavaScript还支持自动在语句末添加分号,允许忽略语句末尾的分号。[29]
JavaScript是弱类型的,这意味着变量可以被隐式转换为另一个类型。[30]
+
会把两个操作数转换为字符串,除非两个操作数都为数字类型。[31]这是因为+
也表示字符串连接操作;-
会把两个操作数转换为数字类型;[32]+
和-
,都会把操作数转换为数字。下列为变量转换为字符串的例子:
,
分隔的长字符串;[object Object]
,其中Object
中该对象的构造函数名。[33]类型的隐藏转换是JavaScript受到批评的原因之一,因为隐藏转换增加了规则的复杂度和发生错误的可能性。[34]
左操作数 | 操作符 | 右操作数 | 结果 |
---|---|---|---|
[] (空数组)
|
+
|
[] (空数组)
|
"" (空字符串)
|
[] (空数组)
|
+
|
{} (空对象)
|
"[object Object]" (字符串)
|
false (布尔值)
|
+
|
"" (空字符串)
|
"false" (字符串)
|
"123" (字符串)
|
+
|
1 (数字)
|
"1231" (字符串)
|
"123" (字符串)
|
-
|
1 (数字)
|
122 (数字)
|
JavaScript是动态类型的语言,其类型与值而不是与变量相关联。例如变量可以为数字,随后又可被赋值为字符串。JavaScript提供了包括鸭子类型在内的方法来检测变量类型。
JavaScript提供eval()
函数,可以在运行时直接执行JavaScript语句。[37]
在JavaScript中,对象是关联数组,通过原型(prototype
,见下)进行扩充。每一个字符串键值提供对象的一个属性的名称,可以通过使用点号(obj.x
)或使用方括号(obj['x']
)这两种效果相同的方式来访问。属性可以在运行时添加、重定义或删除。一个对象的大多数属性(包括来自原型继承链的属性)都可以通过 for...in
循环访问。[38]
JavaScript使用原型,而许多其它面向对象语言使用类用于实现继承。原型使得在JavaScript中模拟基于类的面向对象特征变成可能。[39]
函数在JavaScript中兼作为对象构造函数。在函数调用前加上new
会创建一个原型的实例,并继承来自构造函数的属性和方法(包括来自Object
原型)。[40]ECMAScript 5提供Object.create
方法,可以显式地创建实例而不是自动从Object
继承。[41]构造函数的prototype
属性决定了用于新对象的内部原型。可以通过修改构造函数的原型的方法来为对象添加新的方法,也可以修改JavaScript的内部对象的原型(如Array
或Object
)。尽管可以这么做,但对Object
原型进行修改并不是好的做法。因为大多数JavaScript对象都会从Object
继承,且不会希望其原型被修改。[42]
和大多数面向对象的语言不同,在JavaScript中函数定义和方法定义没有明显区别。唯一的区别在于调用时:当函数被作为方法调用时,函数的this
会指向调用此函数的对象。[43]
ECMAScript 2015中加入了对class
和extends
关键字的支持,使得类的定义与继承更类似于其他的面向对象语言,同时也更易使用。[44][45]
在JavaScript中,函数是一等的,函数也被认为是对象。因此,函数可以有属性和方法,例如call()
和bind
等。[46]嵌套函数指定义于其它函数内部的函数,在外部函数被调用时,嵌套函数会被创建。另外,嵌套函数是一个闭包,在外部函数的作用域(包括常量,局部变量和参数)都成为内部函数状态的一部分,甚至在外部函数执行完毕后,内部函数的状态依然保留[47]。JavaScript同时也支持匿名函数[48]。
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一般来说是单线程的。[49]为了并发地处理事件,JavaScript程序输入或输出时使用事件和回调函数执行。这意味着JavaScript可以在等待数据库查询返回信息之前处理鼠标单击。ECMAScript 2015引入了Promise
用于处理异步事件,其可以使得传统的基于回调的异步代码更加清晰简单。[50][51]
JavaScript中函数参数的长度是可变的,在函数内部可以通过arguments
对象访问这些参数。[52]
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>
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)。
下列表格的資訊基於多個參考來源[53][54][55][56]:
版本 | 發布日期 | 基於 | 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[57] | |||
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[58] + 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 |
looklikejava
的参考文献提供内容origin
的参考文献提供内容