Javascript: 編程語言

JavaScript(通常缩写为JS)是一门基于原型和头等函数的多范式高级解释型编程语言,它支持面向对象程式設計、指令式编程和函数式编程。它提供方法来操控文本、数组、日期以及正则表达式等。不支持I/O,比如网络、存储和图形等,但这些都可以由它的宿主环境提供支持。它由Ecma通过ECMAScript实现语言的标准化。目前,它被世界上的绝大多数网站所使用,也被世界主流浏览器(Chrome、Firefox、Safari和Opera)所支持。

JavaScript
Javascript: 历史, 概論, 特性
JavaScript源代码截图
编程范型事件驱动函数式指令式
設計者创造者布蘭登·艾克ECMAScript规范的其他关键贡献者
发行时间1995年12月4日,​28年前​(1995-12-04
当前版本
  • ECMAScript 2023 (2023年6月;穩定版本)
  • ECMAScript 2025 (2024年3月27日;預發佈版本)
編輯維基數據鏈接
型態系統动态类型鸭子类型
文件扩展名
  • .js
  • .cjs
  • .mjs
網站www.ecma-international.org/publications-and-standards/standards/ecma-262/ 編輯維基數據鏈接
主要實作產品
V8JavaScriptCoreSpiderMonkeyChakra
啟發語言
AWKCHyperTalk英语HyperTalkJavaLuaPerlPythonSchemeSelf
影響語言
ActionScriptAtScript英语AtScriptCoffeeScriptDartJScript .NETLiveScript英语LiveScriptObjective-J英语Objective-JOpa英语Opa_(programming_language)QMLRakuTypeScript
JavaScript
Javascript: 历史, 概論, 特性
扩展名
.js
互联网媒体类型
application/javascript
text/javascript (obsolete)
统一类型标识com.netscape.javascript-source
格式类型脚本语言

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

对于客户端来说,JavaScript通常被实现为一门解释语言,但如今它已经可以被即时编译(JIT)。随着HTML5CSS3语言标准的推行,它还可以用于游戏、桌面和移动应用程序的开发,以及在服务器端网络环境运行(如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最著名的實現之一。除此之外,ActionScriptJScript也都是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引发了 Web 浏览器之外 JavaScript 使用的显着增加。Node 结合了V8引擎、事件循环和I/O API,从而提供了独立的 JavaScript 运行时系统。截至 2018 年,Node 已被数百万开发人员使用,并且npm拥有世界上所有包管理器中最多的模块。

ECMAScript 草案规范目前在GitHub上公开维护,并通过定期的年度快照生成版本。对语言的潜在修订通过全面的提案流程进行审查。现在,开发人员不再单独检查即将推出的功能的状态,而不是版本号。

当前的 JavaScript 生态系统拥有许多库和框架、已建立的编程实践以及在 Web 浏览器之外大量使用 JavaScript。另外,随着单页应用程序和其他大量使用 JavaScript 的网站的兴起,已经创建了多个转译器来帮助开发过程。

概論

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

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

JavaScript的基本特点如下:

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

JavaScript常用来完成以下任务:

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

特性

不同於伺服器端腳本語言(如PHPASP),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中的隐式转换:
左操作数 操作符 右操作数 结果
[](空数组) + [](空数组) ""(空字符串)
[](空数组) + {}(空对象) "[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的内部对象的原型(如ArrayObject)。尽管可以这么做,但对Object原型进行修改并不是好的做法。因为大多数JavaScript对象都会从Object继承,且不会希望其原型被修改。

函数作为方法

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

传统的类定义与使用格式

ECMAScript 2015中加入了对classextends关键字的支持,使得类的定义与继承更类似于其他的面向对象语言,同时也更易使用。

函数式

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

其它

运行时环境

JavaScript通常依赖于运行时环境(例如浏览器)来提供对象和方法,脚本可以通过这些对象和方法与环境(例如网页DOM)进行交互。它还依赖于运行时环境来提供包或导入脚本(例如HTML