JavaScript
JavaScript
JavaScript(通常缩写为JS)是一门基于原型和头等函数的多范式高级-{zh-hans:解释型;zh-hant:直译}-编程语言,它支持面向对象程式设计、指令式编程和函数式编程。它提供方法来操控文本、数组、日期以及正则表达式等。不支持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年首次推出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引发了 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在过去只支持使用codice_1关键字来定义变量的函数作用域,但ECMAScript 2015中加入了codice_2关键字来支持块级作用域。这意味着JavaScript现在既支持函数作用域又支持块级作用域。JavaScript还支持自动在语句末添加分号,允许忽略语句末尾的分号。
弱类型.
JavaScript是弱类型的,这意味着变量可以被隐式转换为另一个类型。
下列为变量转换为字符串的例子:
类型的隐藏转换是JavaScript受到批评的原因之一,因为隐藏转换增加了规则的复杂度和发生错误的可能性。
动态化.
类型.
JavaScript是动态类型的语言,其类型与值而不是与变量相关联。例如变量可以为数字,随后又可被赋值为字符串。JavaScript提供了包括鸭子类型在内的方法来检测变量类型。
运行时估值.
JavaScript提供codice_11函数,可以在运行时直接执行JavaScript语句。
基于原型的面向对象.
在JavaScript中,对象是关联数组,通过原型(codice_12,见下)进行扩充。每一个字符串键值提供对象的一个属性的名称,可以通过使用点号(codice_13)或使用方括号(codice_14)这两种效果相同的方式来访问。属性可以在运行时添加、重定义或删除。一个对象的大多数属性(包括来自原型继承链的属性)都可以通过 codice_15循环访问。
原型.
JavaScript使用原型,而许多其它面向对象语言使用类用于实现继承。原型使得在JavaScript中模拟基于类的面向对象特征变成可能。
函数作为对象构造器.
函数在JavaScript中兼作为对象构造函数。在函数调用前加上codice_16会创建一个原型的实例,并继承来自构造函数的属性和方法(包括来自codice_10原型)。ECMAScript 5提供codice_18方法,可以显式地创建实例而不是自动从codice_10继承。构造函数的codice_12属性决定了用于新对象的内部原型。可以通过修改构造函数的原型的方法来为对象添加新的方法,也可以修改JavaScript的内部对象的原型(如codice_21或codice_10)。尽管可以这么做,但对codice_10原型进行修改并不是好的做法。因为大多数JavaScript对象都会从codice_10继承,且不会希望其原型被修改。
函数作为方法.
和大多数面向对象的语言不同,在JavaScript中函数定义和方法定义没有明显区别。唯一的区别在于调用时:当函数被作为方法调用时,函数的codice_25会指向调用此函数的对象。
传统的类定义与使用格式.
ECMAScript 2015中加入了对codice_26和codice_27关键字的支持,使得类的定义与继承更类似于其他的面向对象语言,同时也更易使用。
函数式.
在JavaScript中,函数是一等的,函数也被认为是对象。因此,函数可以有属性和方法,例如codice_28和codice_29等。嵌套函数指定义于其它函数内部的函数,在外部函数被调用时,嵌套函数会被创建。另外,嵌套函数是一个闭包,在外部函数的作用域(包括常量,局部变量和参数)都成为内部函数状态的一部分,甚至在外部函数执行完毕后,内部函数的状态依然保留。JavaScript同时也支持匿名函数。
其它.
运行时环境.
JavaScript通常依赖于运行时环境(例如浏览器)来提供对象和方法,脚本可以通过这些对象和方法与环境(例如网页DOM)进行交互。它还依赖于运行时环境来提供包或导入脚本(例如HTML的codice_30元素)的功能。这本身不是语言功能,但在大多数JavaScript实现中很常见。
承诺.
JavaScript的“承诺”(codice_31)是一种编程模型,它允许表示可能在未来某个时间点完成或失败的值。承诺被设计为一个解决异步编程中所遇到的问题的更简洁和一致的方法。相比于传统的回调函数,它为处理异步操作提供了一个更清晰的方式。
一个承诺有三种状态:
待定(Pending): 初始状态,既不是成功也不是失败。
已履行(Fulfilled): 意味着操作成功完成。
已拒绝(Rejected): 意味着操作失败。
承诺的主要特点是它们的状态一旦改变(从待定到已履行或已拒绝),就不能再次改变。这使得承诺成为一个可靠的信息来源,无论它们是否成功。
在JavaScript中,你可以使用codice_32方法来附加回调函数,这些回调函数会在承诺达到已履行或已拒绝状态时执行。还有一个codice_33方法,专门用于处理被拒绝的承诺。为了使链式调用更简洁,codice_32和codice_33都会返回一个新的承诺。ES6(ECMAScript 2015)引入了原生的codice_31对象,从此承诺成为JavaScript标准的一部分。此后的版本还提供了额外的实用方法,例如codice_37和codice_38,用于处理多个承诺。
异步.
JavaScript一般来说是单线程的。为了并发地处理事件,JavaScript程序输入或输出时使用事件和回调函数执行。这意味着JavaScript可以在等待数据库查询返回信息之前处理鼠标单击。ECMAScript 2015引入了codice_31用于处理异步事件,其可以使得传统的基于回调的异步代码更加清晰简单。
变长参数.
JavaScript中函数参数的长度是可变的,在函数内部可以通过codice_40对象访问这些参数。
编程.
JavaScript是一门脚本语言,其原始码在客户端执行前不需经过编译,而是将文本格式的字符代码发送给浏览器,由浏览器解释执行。直译语言的弱点是安全性较差,而且在JavaScript中,如果一条语句执行不了,通常它下面的语言也就无法执行。解决办法是使用异常处理codice_41︰
-{zh-hans:
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) {} //这是正确的
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︰
-{zh-hans:
document.write("Hello, world!"); // 直接插入页面中
alert("Hello, world!"); // 弹窗显示
console.log("Hello, world!"); // 在控制台(console)里显示,需要先开启开发工具控制台
HTML内容……
document.write("Hello, world!"); // 于浏览器视窗内直接显示
alert("Hello, world!"); // 开启对话视窗显示
console.log("Hello, world!"); // 于console里显示,需要先开启开发工具控制台
HTML内容……
或是在浏览器的地址栏中使用codice_42,以互动方式表示:
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)。
下列表格的资讯基于多个参考来源:
外部连结.
-{H|zh-hans:重定向;zh-hant:重新导向;}--{H|zh-cn:字符;zh-tw:字元;}--{H|zh-hans:文件; zh-hant:档案;}--{H|zh-hans:快捷方式; zh-hant:捷径;}--{H|zh-hans:项目;zh-hant:专案;zh-tw:计划;zh-hk:计划;zh-mo:计划;}--{H|zh-cn:计算机; zh-sg:电脑; zh-tw:电脑;}-
-{H|zh-hans:汇编语言;zh-hant:组合语言}-
-{H|zh-hans:标记语言;zh-hant:置标语言}-