首页 存档 技术 查看内容

JavaScript的演变史,它在走向何处?(上篇)

2018-3-30 13:00 |来自: 互联网 273 0

摘要: JavaScript 毋庸置疑是当今最重要的语言之一。Web 的兴起已经把 JavaScript 带到一个前所未有的地步。下面我们来看看 JavaScript 在其短短历史中是如何演变的,以及它在走向何处。请继续读下去! 这一切都开始于九 ...

JavaScript 毋庸置疑是当今最重要的语言之一。Web 的兴起已经把 JavaScript 带到一个前所未有的地步。下面我们来看看 JavaScript 在其短短历史中是如何演变的,以及它在走向何处。请继续读下去!


这一切都开始于九十年代

一切都发生在 1995 年 5 月到 11 月这六个月内。网景通讯公司在早期的 Web 中拥有强大的地位。它的浏览器 Netscape Communicator,作为第一款流行 Web 浏览器 NCSA Mosaic 的竞争对手,正获得广泛认同。网景是由 90 年代早期参与 Mosaic 开发的同一伙人创立的,而现在,有了钱和自主性,他们就有了寻求进一步扩展 Web 的途径所需的自由。而这种自由催生了 JavaScript。

网景通讯的创始人及前 Mosaic 团队的成员 Marc Andreessen 预见到 Web 需要某种方法变得更动态。动画、交互和其它形式的小动画应该是未来 Web 的一份子。所以 Web 需要一种能与 DOM 交互(不是跟你现在看到的这样一成不变)的小脚本语言。不过,这种脚本语言不应该面向大佬开发者,以及在软件工程方面有经验的人们在当时这是一种重要的战略呼声。当时 Java 也在兴起,并且 Java applets 很快就要成为现实。所以这个用于 Web 的脚本语言需要迎合另一群受众:设计师。实际上,那时 Web 是静态的。HTML 依然年轻,并且足够简单,非程序员也很容易学得会。所以,要让 Web 变得更动态,不管是浏览器的哪一部分,都应该让非程序员容易理解。这样 Mocha 的想法就诞生了。Mocha 要成为用于 Web 的一种脚本语言,它必须是简单、动态的,并且让非程序员容易理解。

此时,JavaScript 之父 Brendan Eich走上了历史舞台。网景通讯公司雇佣 Eich,是让他开发一种 “用于浏览器的 Scheme。Scheme 是一种 Lisp 的方言,语法很简单,它动态而强大,并且本质上是函数式的。而 Web 需要类似这样的语言:语法容易掌握;动态的,以减少代码,加快开发;并且强大。Eich 看到有机会可以从事自己喜欢的事情,于是就入伙了。

当时,迫于压力,必须尽快赶出一个工作原型。当时原名为 Oak 的 Java 语言正开始推动。Sun Microsystems 正大力推进 Java,网景通讯公司即将与他们达成一项协议,让 Java 可以用在浏览器上。那么为什么要开发 Mocha(JavaScript 早期的名字)呢?为什么已经有了 Java,却还要开发一个全新的语言呢?当时的想法是,Java 不适合 Mocha 的目标受众:测试脚本编写人员、业余爱好者、设计师。对于用在浏览器这个角色上来说,Java 确实太大太重了。所以当时他们的想法是让 Java 用于大型专业级组件开发;而 Mocha 将用于小型脚本任务。也就是说,Mocha 命中注定就是 Java 的脚本同伴,在某种程度上类似于 Windows 平台上 C/C 和 Visual Basic 之间的关系。

与此同时,网景的工程师开始详细地研究 Java。他们甚至开始开发自己的 Java 虚拟机。不过,这个虚拟机很快被否决,因为它从来就没有实现与 Sun 的虚拟机的完美一致。

此时有很多来自于内部的压力,要尽可能快地选择一门语言。Python、Tcl 以及 Scheme 本身都是可能的候选。所以,Eich 必须快。不过,他比别人有两个优势:可以自由挑选适合的特性集、可以直达拍板的人。不幸的是,他也有一个大的劣势:没有时间。必须要做出很多重要的决定,而做出决定的可用时间又很短。JavaScript,即 Mocha,就是在这种背景下诞生的。几周之内,一个工作原型就推出了,然后就被集成到 Netscape Communicator 中。

于是,本应是用于浏览器的 Scheme,现在就大相径庭了。与 Sun 达成协议的压力,以及让 Mocha 变成 Java 的脚本同伴,束缚住了 Eich 的手脚。新语言需要采用类似 Java 的语法,对于很多常用语还采用了熟悉的语义。所以 Mocha 一点也不像 Scheme。它表面上看像是一种动态的 Java,实际上却是Scheme 和 Self 的早产私生子,但长的像 Java。

1995 年 5 月, Mocha 的原型被集成到 Netscape Communicator 中。很快,它被重命名为 LiveScript。当时,"live" 这个单词只是为了营销方便。1995 年 12 月,网景通讯公司和 Sun 达成协议:Mocha/LiveScript 将被重新命名为 JavaScript,它将会作为浏览器中小型客户端任务的一种脚本语言,同时 Java 将会被提升为一种更大的、开发富 Web 组件的专业工具。

第一版的 JavaScript 敲定了该语言中很多现在知名的特性,特别是其对象模型以及函数式特性在此版本中已经出现了。

如果当时 Eich 未能按时赶出一个工作原型,很难说会发生什么。其他可选方案一点也不像 Java。Python、Tcl 和 Scheme 都与 Java 大不相同。对于 Sun 公司来说,很难接受一个与 Java 如此不同的同伴语言,或者在历史和开发上比 Java 本身早的语言。另一方面,Java 很长一段时间是 Web 的一个重要部分。如果 Sun 从没有过这样的地位,网景可能会在挑选这样一个语言上有更多的自由。这是肯定的。不过,如果就算网景自己内部能控制和开发,它会不会选择采用外部的解决方案呢?我们将永远不会知道。

不同的实现

当 Sun 和 Netscape 达成协议,将 Mocha/LiveScript 的名称改为 JavaScript 时,有个大问题被提出来了:其他实现会怎么办?实际上,尽管 Netscape 很快成为了当时首选的浏览器,不过微软也正在开发 Internet Explorer。从最开始,JavaScript 就带了用户体验如此大的差异,竞争浏览器没办法,只能自己也整一套 JavaScript 的实现。此时(并且很长一段时间),Web 标准还不强大。所以微软实现了自己版本的 JavaScript,叫做 JScript。从名称中去掉 “Java”,是为了避免潜在的商标问题。不过,JScript 不仅仅是名称上的不同。它在实现上也略有不同,特别是与某些 DOM 函数有关的实现上有所不同,由此产生的影响一直波及到多年之后的未来。JavaScript 大战还发生除了名称和时间表之外的更多方面上,而它的怪癖正是这些大战打来的创伤。JScript 的第一个版本包含在 1996 年 8 月发布的 IE 3.0 中。

网景的 JavaScript 实现也采用了一个内部名称。和 Netscape Navigator 2.0 一起发布的版本被称为 Mocha。在 1996 年秋天,Eich 为了偿还匆忙推出它所欠下的技术债,将 Mocha 的大部分重写为一个更干净的实现。这个新版本的网景 JavaScript 引擎叫做 SpiderMonkey。SpiderMonkey 现在依然是 Netscape Navigator 的孙子 Firefox 中 JavaScript 引擎的名称。

有好几年,JScript 和 SpiderMonkey 是主要的 JavaScript 引擎。二者共同实现的功能(并非总是兼容)会定义接下来几年中 Web 的样子。

主要设计特点

尽管 JavaScript 是仓促之作,不过有几个强大的特性在一开始就具备了。这些特性将 JavaScript 定义为一门语言,尽管有各种怪癖,依然让它能独树一帜。

是使用一门已有的语言,还是发明一门新的语言,这也不是我能决定的。来自高层工程管理人员的强制命令是这门语言必须“看起来像 Java ”。这实际上也就把 Perl、Python、 Tcl 以及 Scheme 这些已有的语言排除掉了。后来,在 1996 年,John Ousterhout 在给 Tk 做宣传时还感叹说,Tcl 错过了这样一个很好的机会。我并非骄傲,只不过是很高兴我选择 Scheme 式的一等函数以及 Self 式(尽管很怪异)的原型作为主干。至于 Java 的影响,主要是把数据分成基本类型和对象类型两种(比如字符串和 String 对象),以及引入了Y2K 日期问题,这真是不幸。 -Brendan Eich 的博客:关于流行

类 JAVA 的语法

尽管让 JavaScript 语法接近 Java 并非初衷,不过市场力量让它变成了这样。退一步想,即使采用与 Java 不同的语法可能会让实现某些特性更为方便,但是不可否认,采用熟悉的语法更有助于 JavaScript 的普及。

将如下的 Java 示例:

public class Sample {
public static void main(String[] args) {
System.out.println("Hello world!");
try {
final MissileSilo silo = new MissileSilo("silo.weapons.mil");
silo.launchMissile(args[0]);
} catch(Exception e) {
System.out.println("Unexpected exception: " e);
}
}}

与如下(现代) JavaScript 示例做比较:

console.log('Hello world');try {
const silo = new MissileSilo('silo.weapons.mil');
silo.launchMissile(process.argv[0]);} catch(e) {
console.log('Unexpected exception' e);}

函数作为一等对象

在 JavaScript 中,函数只是又一个对象类型。它们可以像任何其它元素一样传递,可以被绑定到变量。在稍后版本的 JavaScript 中,函数甚至可以被抛出为异常。这个特性很有可能是在 JavaScript 开发时受到 Scheme 强烈影响的结果。

var myFunction = function() {
console.log('hello');}otherFunction(myFunction);myFunction.property = '1';

通过让函数变成一等对象,某些函数式编程模式才成为可能。例如,较新版本的 JavaScript 利用了某些函数式模式:

var a = [1, 2, 3];a.forEach(function(e) {
console.log(e);});

这些模式已经被成功用于很多库,比如underscoreimmutable.js

基于原型的对象模型

尽管基于原型的对象模型是通过 JavaScript 得以流行的,不过它却是在 Self 语言中首次引入。Eich 对这种模型有种强烈的偏好,它足够强大,能够模仿像 Java 或 C 这种基于 Simula 的语言中的更传统的方式。实际上,JavaScript 之后的版本中实现的类,也只不过是在原型系统之上的语法糖。

JavaScript 的原型灵感来自于 Self,而 Self 的设计目标之一就是要避免 Simula 风格的对象的问题。特别是,在 Simula 的方式下,类和实例之间的对立被看到是很多固有问题的诱因。有人认为,因为类为对象实例提供某种原型,随着代码演变和逐渐变大,就越来越难让这些基类适应不可预料的新需求。通过将实例作为新对象构建的原型,这种**就被克服了。因此,原型的概念是:一个通过提供自己的行为,填补新实例的空白的实例。如果一个原型被认为不适合于一个新对象,那么它只需要被克隆和修改,而不会影响所有其它子实例。这在基于类的方式中是挺难做到的(即,修改基类)。

function Vehicle(maxSpeed) {
this.maxSpeed = maxSpeed;}Vehicle.prototype.maxSpeed = function() {
return this.maxSpeed;}function Car(maxSpeed) {
Vehicle.call(this, maxSpeed);}Car.prototype = new Vehicle();

原型的威力让 JavaScript 变得超级灵活,引发了很多带有自己对象模型的库的开发。一个流行的库Stampit就重度使用了原型系统,采用在基于类的传统方法下不可能的方式,来扩充和操作对象。

原型让 JavaScript 表面上看起来简单,但是给库的作者带来了自主权。

大怪癖:基础类型与对象

也许在匆忙开发的 JavaScript 中,最大的错误之一是某些行为类似的对象有不同的类型。例如,字符串字面量("Hello world")的类型与String对象(new String('Hello world'))的类型就是不相同的。这就让我们有时候不得不采用不必要的、容易混淆的类型检查。

声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部