JavaScript真的继承自Cmm吗?
, t% U% p+ C8 V6 PJavaScript与Java有多少关系?
: W, }9 r7 ?6 P, T
JavaScirpt最初的设计是怎样的?
* `) Q4 J' D0 ]- [# c9 R3 j
]0 h, D* r1 ^$ C: V/ B在许多资料,JavaScript的语源被追溯到一种名为Cmm的语言。同样是在这一溯源的过程中,人
- _8 n! u' Y2 _, ?$ U* l们发现“其实”JavaScript不是第一种网页中的脚本语言。现在一些所谓“公认”的情况是这样的:
6 t- R7 V5 i9 R Y1 E/ l" k----------------
& {% j, I" t' R
大概在1992年,一家称作Nombas的公司开始开发一种叫做C减减(C-minus-minus,简称Cmm)的
+ b! U$ Y' e% f' Y" h
嵌入式脚本语言。这个脚本语言捆绑在一个叫做CEnvi的共享软件产品中,当Netscape Navigator
) c n( t, P2 R( m崭露头角时,Nombas开发了一个可以嵌入网页中的CEnvi的版本。这些早期的试验称为Espresso
4 ~: X8 P- v7 L& c; C! {8 yPage(浓咖啡般的页面),它们代表了第一个在万维网上使用的客户端脚本语言。而Nombas丝毫
# e: H: v, C# ]5 I( i- s5 B没有料到它的理念将会成为因特网的一块重要基石。
' q! l3 u! m. @ V4 i5 y----------------
* B1 v$ t7 u$ b' n* a8 Y( R
' ~/ Z) i3 n$ c8 ~( j* q9 c
然而,这是真实的情况吗?运行在Netscape中的第一个“客户端脚本语言”真的是Cmm的浓咖啡?
7 O( z; m. J, o( n. R2 T
又或者真的象Wiki中记述的那样,Brendan Eich在JavaScript引用了Cmm语言特性?
! V3 Z9 F0 V- k. [ H+ s2 [0 X0 r# i$ q+ R! Q9 E; Y
不是的。尽管上述的资料看起来出权威:《Javascript高级程序设计》(Professional JavaScript
! a( ~$ w1 L# n1 n/ Lfor Web Developers),但他的确错了。
4 D8 [+ s2 b, ^$ |- L1 l! y
. z1 ?3 `# F7 D, j2 X
* {6 t5 ]; v3 q+ ?, `! W3 v
JavaScript与Cmm在语言特性上无关
4 X! g3 L, S6 G; G, J: T============
% r+ T2 \8 N7 f4 _
为了弄明白JavaScript与Cmm的关系,我大概用了三天的时间,从网上收集了多个Cmm的版本。这
$ V! y; `8 l+ o6 u( `
些版本既包括早期的Cmm(1993年),也包括在JavaScript初创时的Cmm(1995年),还包括在后来,
1 h. |1 J2 z& k5 c5 f, ^9 ^5 p! ~
Cmm更名为ScriptEase的第一个版本(3.0, 1997年),作为参考,我还考察了它在服务器端的版本。
m+ }7 A2 t- [/ u) a. n- C* I
( k* `" Z; D" K; A4 R T' a遗憾的是,在1996年之前,在Cmm的2.x的最后一个版本之前,Cmm都并不是一个面向对象(或基于
2 R0 u- P$ t- I9 C& j对象)的语言,Cmm正如它自己的名字所说的一样:是一个精减版的C,而不是C++或以C++为基础
6 s7 ?9 R0 d7 f7 x; |6 o
的变种。所以Cmm中有“结构”,也有#include等,整个的体系是参考C语言的。
, P4 `1 e0 h8 D) n% w% q1 L
9 Q% G/ ~. y0 B" k由于JavaScript在基本的语法特性(例如大括号、语句关键字等)上参考了C,在对象系统上(例
& h# e0 U, n7 y w+ C
如“.”作为成员存取)上参考了Java,因此在一定程度上Cmm与JavaScript存在相似性——主要是
5 Z- D# X9 Q6 U
与共同借鉴自C的部分。但是除了这些之外,JavaScript与Cmm在语言特性上完全无关。
! B% a7 v/ Z- ?/ t% j% P! f* H4 r) u( _) \8 K% g
6 ^# i7 `! W \3 I0 AJavaScript最初的基本设计是怎样的?
% U; q! k' V2 z
============
2 O# h) H/ \" K9 b" W我需要补充一下JavaScript初始设计目标。Brendan Eich在1995年4月前后被Netscape公司雇佣,
$ k. y) ^5 p3 w目标是完成一套语言系统。最初的设计里,该语言系统是为Netscape的LiveWire战略服务的。该
5 `! W7 t x3 F6 T3 W! g/ C, g战略彰显了Netscape当年的勃勃野心,它是Netscape公司的一个通用的Web开发环境,包括Netscape
0 r ^' X+ i( G3 o p0 |Enterprise、FastTrack Server等。LiveWire架构也成为所有Web服务器提供SP(Server Page)技
! L% ]" S6 G r3 l g$ g$ \
术的蓝本。例如在IIS中的ASP,以及更早期的IDC(Internet Database Connect)。
6 V9 K) I8 W8 I% n8 [
* g* K, i( A) `. C这种技术在服务器端通过内嵌于网页的LiveScript代码,使用名为database、DbPool、Cursor等
2 b0 D2 s2 n% W( s3 g7 N# S5 c
的一组对象来存取LiveWire Database。作为整套的解决方案,Netscape在客户端网页上也提供
. I5 P- L' b7 b1 ]* w7 aLiveScript脚本语言的支持,除了访问Array、String等这些内置对象之外,也可以访问window等
' |7 J) t2 s$ a0 ?浏览器对象。
9 G" G$ ^" l, [5 q4 ~, V& R5 A
+ U) j( y3 n% h/ j& O不过并不清楚的是:LiveScript最初的设计是先考虑服务器端应用,还是先考虑网页中应用。但这
- K+ `/ V; m8 x' c! {2 q# u5 C0 {些应用环境的决策上的变化,时间仅仅限制在1995年4月至1995年10月之前,因为当月发布的netscape
( @9 u5 E: l6 h# S
2.0 beta1已经包含了脚本支持。
. q9 }( V; c' C# X% }2 B+ {8 i6 S% g" N3 X1 Z
在netscape 2.0 beta1中并不支持<script>标签,而只是在form表单元素中支持了onclick这类的
% U4 h e% Q5 u, R事件。这时的脚本代码是用在HTML标签属性上的,也就是类似于:
! c& B/ v3 w; j( E* g5 X
<input type="button">
2 a; `. T+ C; g* p" `. E很快,三周之后netscape 就发布了beta2。这个版本正式地支持了<script>标签,并可以解析该标签
+ U4 F6 Q' f( G中的代码、标识符,开始具备调用函数、表达式运算等能力。这个版本已经具备了JavaScript 1.0
6 c% m+ k8 c3 ~5 \* \的基本性质。
. k1 @- |% u, G! n4 e( c7 b
: H5 V8 }4 U7 D5 k——什么?能调用函数、表达式运算就是JavaScript 1.0的基本性质了?
9 C4 O+ H# N# L) c0 h! W
# O9 w3 Z5 S& P. Z是的,差不多了。相比起来,JavaScript 1.0只是在这样的基础上加上了一套对象系统而已。在随
2 \5 j' A6 W" M4 z: H! t. K
后发布的beta 3中,函数可以作为构造器使用,可以创建出用户自己的对象来了。再后来window等
+ M) t& h( {0 x- i" i. ^3 A( Z; g全局对象被加了进来,再把“当前网页”中的表单元素等影射成可编程对象,JavaScript 1.0就完
9 S0 e* K8 `" R2 \8 j0 p
成了。
% }8 }. h" a8 ~! y! L7 e8 S- w4 x' H8 Q# C: z" E9 a h' X
仅仅如此而已。在JavaScript 1.0的时代,既没有“原型继承”,也没有“函数式编程”——甚至
& ~! L' y- r- V* ]0 t( Z! f6 _
连匿名函数也没有支持,所以下面的代码就足够让浏览器挂掉了:
A( E$ ^% I3 Z8 m. q" i* P----------------
, h( R/ ~0 I$ q: S3 C1 Y4 e
var func = function() {
1 {6 G+ h' f9 \$ F K I/ f9 v, `, [7 M}
7 R% K: Y; Q- F) S: l! ^7 Z+ V
----------------
- s- E" c0 s4 g: l
1 v/ U6 a; Y0 J7 e2 D1 Y
JavaScript 1.0的设计目标,就是“让网页动起来”,最初的要求包括三个方面:
& \7 W4 O6 h, ]) E! [
- 让网页中的元素可以被编程,所以象forms、links这些对象,在网页装载结束后就初始化为全
+ e$ V; |- V: Q
局成员了——那时候还没有所谓的DOM或DHTML呢。
0 Z, l7 r$ z5 L. l5 w/ P# Z2 {) \/ K' A- 让JavaScript跟Java接近一些,因为Netscape与Sun有战略合作。而且,Sun那时相当火暴。
5 k. r, j# o; R3 m* Z, r9 u8 Y% W
- 让JavaScript可以在服务器与客户端两边都使用,因此它必须是嵌入式的。
8 A1 i* u% y2 X. W' j* P! M/ ^& Z
不过JavaScript的另一项特性,则自它的第一个版本就存在。该特性就是动态执行,也就是eval()。
5 Y' c# x) e0 g) w$ Z这是与它的“脚本”的性质有关的。在早期的“脚本”也被称为“批处理程序”,就如同DOS批处理
2 Z! _0 |, ~8 G8 z' n% w) Z或Unix shell一样,脚本应当具有装入字符串文本并“动态执行”的能力。
& m* u" f" e n' B
: q5 A( w& A0 u所以总结起来,JavaScript 1.0其实是一个可以创建和操作对象的普通过程式语言。这个时候的JS
! A; s' A1 Y% \) C8 s
代码既不能检测“对象-构造器”之间的继承性,也没有原型继承这样的东东来构建对象系统。函数
# Z9 g. d" r# `5 e
除了在new MyObject()时协助传入一个this引用之外,就跟普通的函数完全一样。而且,最为有趣
3 |( L R B# G* T的是,Brendan Eich这时还没有形成JavaScript中最重要的“类型系统”概念,此时undefined还只
/ U% u! h4 X5 ^8 E) W
是系统全局中的一个特殊的值,而不是某种类型。typeof关键字也还根本不存在。换言之,Eich现
' E8 A. @8 W. j5 a: m
在要做的只是一个“可编程的、可以用对象的”脚本语言,至于它是否在类型系统上完备或者优美,
0 `, e/ v7 B o9 D3 \
他还顾不过来呢。
$ b; y: m3 R: }% {0 Y
! @# J* s, i4 {% Z( i0 eJavaScript最重要的“构造器-原型继承”概念是在JavaScript 1.1版本中提出的,类型系统和重要
" u d- e7 S0 k! P( z1 ^! b3 V4 ]的函数式语言特性要等到v1.2之后才被加入。而现在,在1996年1月底,JavaScript 1.0随Netscape
8 j! M# p2 V# y ]2.0正式版发布了。
/ r8 g# u7 }! D2 P: {6 R6 t- \
9 `/ t" N! n) }% H, W
/ m5 o" E# i& B
JavaScript的名字
E ?) _% ^, H4 R============
8 W& @, H1 {* S" W, V4 D r为了弄清楚JavaScript名称和语言特性的演变,我下载了netscape 2.0 beta1~6,以及2.0~2.02所
7 H: Z9 _: ^' p有版本的发布文件,并逐一安装测试。下面解释JavaScript名字的演变过程。
% T; X& L& {' Z$ i C# |( U
4 ^0 S5 L D. |- @/ |( W1 kJavaScript最早是被称为Mocha(魔卡)的,这是这个项目的代码名。这个名字一直用到Netscape
6 X1 a1 H7 q3 n) `, n9 F. h5 @" {, d2.0 beta 2发布之前(95.11.04)——包括在beta 1中弹出的错误框上,还可以看到Mocha的名字。
! V7 O1 G( y O2 ^& U+ s
不过,早在此前的9月18号,netscape就已经发布消息将在LiveWire中启用一种服务器端脚本(未
t, {4 v) L% t) K: _4 @
提及名称)。又因为我们前面提到的“前后端通用脚本”的设计,该语言在beta 2发布时就使用
* ~+ h8 ?* b% e, H! z. F( e2 E了内部名称LiveScript。
6 b) N4 T P8 m6 ]1 K* p' x
( y3 g- Y- a( s- L* n) A: k% {* i但同样混乱的事情是,事实上这时Netscape已经决定将该语言命名为“JavaScript”。因此在
; w5 }0 L* x6 Ebeta 2的发布备忘中该语言称为JavaScript,而界面上却从Mocha改为了LiveScript。这一局面一
1 a- E% I* w3 q3 d; Z9 h
直持续到12月4日,netscape与sun共同发布声明,正式启用了JavaScript这个名字。随后beta 4
' s( P8 ?! f0 E, g发布(95.12.20),界面和文档上就统一了。
7 c/ W* e8 n7 I% ]# Z2 B" @
% O* K; J3 p! F1 ^. r所以事实上“LiveScript”这个名字可以考证的生命周期,也就只有一个月的时间(在95.11.04
7 q% a, V6 J7 B# e- 12.04)。但Mocha毕竟只是项目代码名,而非产品名,所以后来人们追溯JavaScript的历史,
, a& ?3 L3 ?1 ^. Q大多只提到LiveScript为止。
/ R* O s" \/ e' U0 ^1 G* f0 x
5 K1 ^1 h+ O8 c$ x4 X* D
L0 R: l$ R% W+ }+ f* i: R2 R第一段网页内脚本真的是浓咖啡(Espresso Page)吗?
; g2 z" a; V4 m! K0 u. m2 F1 C============
) {/ ]6 t6 _" A8 e1 e如上面所述的,Netscape 2.0的beta 1中就正式加入了脚本支持,最迟在beta 2之前。对象的构
9 Q: _+ q2 e- b0 |$ `; L
建方式、<script>标签的使用,以及在HTML标签上使用onclick这类事件句柄……这些设计就已经
+ H2 ~. U2 H" m+ y A3 ?" Q被明确了。这些是一直延续到现在的,我们最主要的使用网页的方式。
i+ ^, S6 V% y, ^+ W3 P4 t
. V( m7 u. c( a, X. g8 U那么,这个时间点可以不容置疑的被确定在95.11.04之前(beta 2发布之前)。
@5 m$ D1 h6 Q& Q9 N$ J* h& D
* h0 Q |- j' a5 n9 ]1 d我们现在再回过头来看那份讲述Espresso Page的消息。这其实是由Brent Noorda先生(Nombas公
9 V" X/ J7 h( h8 h; A8 g9 n司总裁)于1995.11.27日发布在新闻组上(comp.infosystems.
www.authoring.html)上的一则消息,
% l& L. N: g. p( K' u原文是“这周末我们将放出一些Espresso Pages在我们的网站上(This weekend we put up the
) E) I( c- ^3 S! j7 K5 W3 Y9 t
Espresso Pages, at...)”,那么,也就是Espresso Pages其实出现在11.30号之后。这已经远远
/ t( R( R' `( ?8 |0 X晚于上面的时间了。
. }. I# u; S, \& [6 ]* O% t' z. N; I0 s, ]8 f: t
也就是说,真正第一种在Netscape中使用的客户端脚本,仍然是由Brendan Eich编写的JavaScript。
( k* y9 b8 ^: N J# J' ?0 h这种脚本使用“<script>”标签(在服务器端使用<server>标签),支持五种基本类型(除undefined
( t, k1 f% U0 e- @+ w之外),支持自定义对象和构造器等基本特性,能够操作网页中内嵌的links、forms等对象。
' m" z' H4 w3 Z, y
5 G9 r+ E6 N; F2 I" Q8 a+ ~) O' L3 `然而需要继承说明的是,由于Nombas早早地就实现了Cmm语言以及其开发环境,所以他不需要花什么
6 J, R9 J2 |! {1 E. e! e力气就可以将它们移植到网页中去并展示其非常丰富的能力。所以在Brent Noorda先生在上面的消息
# f$ |! a5 r% c2 f+ {
中说,(周末放出的)这个Demo将演示
" g0 T+ z1 X" C# c! z# Q# k$ O. r; y; w
- a bouncy-button game,
% p# M' Z+ ~ p9 `: j: o
- real-time verification of user input into forms,
! ?* }% t( l( r: V4 n- an animated stick-figure,
# \2 r2 W$ Q* k) m- }6 O$ u" m+ H6 \0 ]
- and a way cool flashback into the psychadellic sixties.
6 M' g5 t2 m: x! J% ]8 f% f的确,这些演示的功能大概是当时的JavaScript(LiveScript)不能实现的。但相同的功能所需求的
4 o( |; Q/ F; Z' P特性以及其基本实现,其实正是Netscape当时已经发布的版本所包含的。所以这里根本就不存在
' _: D9 A& K; V7 t0 q
Netscape抄袭Nombas的问题。然而换一个角度来想,Nombas可能正是看到Netscape发布版本中的种
7 P* A2 @$ j2 }' Z3 X% ~5 c# T
种特性,其实能够用一个嵌入到浏览器中的CEnvi来完成,因此发布了这样的一个示范版本。
9 X2 ?0 Y1 V7 J
' Q. N. V$ y! |9 i! N% a5 f5 `" p2 a从时间先后来分析,我们可以确信的是:
/ H% {3 r( b. W8 y" r
- Netscape在网页中嵌入脚本是早在Espresso Pages出现之前的一个构想;
: _: _5 e. v% c2 J+ E
- JavaScript(LiveScript)是真正的第一个在万维网上使用的客户端脚本语言。
$ L+ J) N* L) N& e, T+ o4 l$ K( h4 C- F/ _; i' f& W
无论如何,Espresso Pages很好地展示了Netscape当时正在图谋的构想——不管是Nombas是与Netscape
4 a0 ?' {; X8 ?* s* b9 {& H s3 }% [' p
想到了一起,还是Nombas帮助Netscape展开了(由Netscape设计的)蓝图。在当时(JavaScript 1.0发
[* T" `3 M5 N. s) B; x5 o
布之前),CEnvi中的Cmm相当完善,开发环境也很成熟。所以可以承认的是,Nombas的Espresso Pages
$ s# o( H3 }) ]7 W$ }
的确更好地展示了Web的末来。但是,成为“因特网的一块重要基石”的构想——这里指页面内脚本,绝
$ d1 D# x5 V3 h& E8 U7 h不是Nombas先创的理念。因为Netscape beta1~3中已经把这些理念都展示了出来。
5 R# ?% r$ E& \1 Y" O6 o$ i4 Y0 f# ?4 }
$ w6 T* W1 h( L" a3 ~
其它
0 m% I9 ~+ A. t$ M) v7 x3 J============
4 r4 V- g/ B7 l/ H1 R D+ U# M9 w
有一种Java的编译器也名为Mocha,但与本文中没有什么关系。
6 R0 v4 e: A& d7 Q k L! m5 |% J" O- A+ Q* n
Cmm也称为C--,但另外还有一种名为Sphinx C--的语言,其设计目标与Cmm类似,但不是同一种语言。
& r6 x. I9 J, r4 a
/ Y% G% F {" T! D2 z- ]; k在Java热火的时代里,出现了很多以浓咖啡(Espresso)命名的产品,但都不是这里的Espresso Pages。
3 N; p8 n ^9 L( O& K
Espresso Pages只是一些Demo页面,需要下载并专用安装一个CEnvi的特定版本才能查看。但这个特定版
; V3 U) |+ x: b: R b本在互联网上已经绝迹了。
% w) d9 U4 l1 s; \# `; i
& M# v l/ V) U) k% KJavaScript并没有从Java中寻找太多灵感,Brendan Eich自己说“my influences were awk, C, HyperTalk,
% s4 B9 y- W1 z/ Fand Self”,这其中既不包括 Java,也没有Cmm的影子。不过Brendan Eich也说另外的影响是“combined
& @+ g& v! {+ v9 t( F: b7 F) y
with management orders to "make it look like Java."这强调的是一种形似,而不是语源上的承继关系。
3 B" R5 u; y9 f, ^. |
5 _- I2 D' x) h3 |在1996年2月,CEnvi发布了最后一个2.x版本。这个版本是对以前版本的一些修补。但接下来,过了约一年
8 N, N) N( s4 W+ q( C1 P' P
半之后,CEnvi才发布下一个版本(v3.0)。从这个版本开始更名为ScriptEase,放弃了旧有的Cmm规格,而
3 m; O3 d3 E# a" i* ~) d
采用了JavaScript规范下的语法。并且自这个版本开始,ScriptEase发布Desktop和Web Server等多种不同
8 B. s: ]! c$ e的版本——此前CEnvi只有针对不同的操作系统的版本。所以事实上,非但不是Brendan Eich受到了Nombas
, n! C4 O9 W; n X. Z7 T
的影响,反而是Nombas受JavaScript而放弃了整个原来的语言设计,而且在产品策略上,还抄袭了Netscape
: M5 B' F+ V/ w1 D
的LiveWire战略。
# I8 C6 m. m3 J; s( F
9 e: V" l' V+ D5 iNombas后来被收购掉,ScriptEase等系列产品不再维护。Nombas.com网站仍然可以访问,但只有一个告别页
, @4 j, G* d; p% v
面,不过相应的,Netscape也好不到哪里去。
9 O5 q' E2 {9 H! O- r
2 N0 q6 }$ U# Y0 ^$ L
Mozilla是Netscape一个早期的Java开发团队的内部代码名。在Netscape 2.0 beta中包含的Java代码包中,
& g5 m+ L; I8 T) ?8 }, s3 k3 S就已经可以看到这一标志了。不过该团队真正独立出来成为开源组织,并最终接手Netscape未竟事业,则
6 f- ^4 X4 I/ A4 O1 b* j
是晚至1998年1月以后的事了。
+ `6 s4 U+ k. w- k
8 r/ K, Y$ M2 s) n
Mozilla与Mozilla Firefox使用两套版本编号。所以“Mozilla 2”是2006.10月开始发起的,而当时Mozilla
1 r6 q# ~- K; l2 a
Firefox 2.0b1已经发布了——它基于“Mozilla 1”的维护版本。同样有趣的是,Mozilla Firefox 3.x则在
- v' i; V* N% n2 H, R- _: F6 E
基于“Mozilla 2”这个项目开发,大概,在2008年中期会发布正式版本。