Netscape 于 1995 年引入了 JavaScript,它很快就流行起来了。最主要的原因是 Web 作为商业媒体平台的出现:使用 JavaScript,您(依然)可以通过编程来影响浏览器中 Web 页面的特性。那这是个很棒的工具!HTML 表单验证与受限图片欺骗(limited image trickery)是主题。
自那时起 JavaScript 就具有多个化身。Netscape 曾一度拥有一个产品,Netscape Application Server,它正是基于服务器端 JavaScript 来构建的 Web 应用程序。多年以后,由于 Ajax 和 Prototype、JQuery、和 Extjs 之类部件库的引入,重新引起了人们对 JavaScript 的兴趣。最近,服务器端 JavaScript 被用于 Node.js 当中,这是利用 Google's V8 JavaScript 引擎构建服务器端 Web 应用程序的基于事件的 I/O 框架。
Netscape 做了一件很有前瞻性的事,就是把 JavaScript 提交到 Ecma International 来进行标准化。这就是人们称 JavaScript 为 ECMAScript 的原因。更重要的是,这也是众多 Web 浏览器支持 ECMAScript 的原因。因此,Web 应用程序大都会采用 JavaScript,这一点没有改变过。目前还没有能与之相比的其他浏览器兼容脚本语言。
当前,尽管 JavaScript 的名声不好,它仍然是应用最广(最有用)的语言之一。如果您是位 Java 程序员(或者 Ruby、Python、或 PHP 程序员),那么您可能曾用过 JavaScript ,或者在不久的将来会使用 JavaScript。了解 JavaScript 的一些特性,有助于构建优秀的 Web 应用程序。此外,这有助于使用 Node.js,甚至还能增强您对 GWT 内部技术的了解。
在下一小节中,我将关注 JavaScript 语法的主要元素,重点介绍一些细节内容,这将有助于 Java 开发人员的提高。然而,我首先想打破一个关于 JavaScript 的神话:就是您需要一个 Web 页面来与其交互。
在过去,JavaScript 需要浏览器,并间接地需要一个 Web 页面来执行。这对于一些开发人员来说是个麻烦,甚至是个障碍。幸运的是浏览器已经发展了;今天不论 Firefox 还是 Chrome 都提供了用于执行 JavaScript 的 IDE。
我喜欢 Chrome 漂亮的 JavaScript 控制台。就像 Ruby's IRB 或者 Python's shell,Chrome 提供不需要 Web 页面的用于浏览 JavaScript 的交互式环境。
想要了解 Chrome's JavaScript 控制台,需要 下载用于您 OS 中的 Chrome。然后,打开一个新的空白标签(也就是说,不要指向 Web 页面)并选择 View > Developer > JavaScript Console。在 Chrome 窗口的底部,会弹出 JavaScript 开发人员控制台。可通过选择控制台左下角的 Undock 图标来使其成为独立对话框。然后可选择右上角的 Console 图标,来打开用于和 JavaScript 交互的空白窗口,如图 1 所示:
图 1. 在 Google Chrome 中与 JavaScript 交互
.
现在来看一些语法。
JavaScript 是一个比较容易使用的语言,它能容忍很多编程错误,并仍然能在加载的 Web 页中执行。JavaScript 元素经常没有任何提示就失败了,这大部分都是好消息。如果 JavaScript 语言草率地禁止页面加载,那么早期的 Web 将是一片混乱。也就是说,当我们利用 JavaScript 来做我们喜欢做的事时(比如异步更新页面状态),草率使用 JavaScript 将付出代价。由于这个原因,Java 开发人员应该花时间真正了解 JavaScript 语法的特定方面。
JavaScript 变量的处理对理解来说很重要。例如,您想定义一个变量 foo
,可以直接定义或者通过 var
声明,如清单 1 所示:
foo = 'foo'
var bar = 'bar'
|
清单 1 中的 foo
是 JavaScript 中的有效变量。但它缺少 var
声明,这是个全局变量。因此利用 var
定义的变量是有范围的(例如,在定义它的函数中)。
通常,全局变量比较麻烦。它们很容易造成变量使用的混乱,因为全局变量可在 JavaScript 应用程序中的任何地方进行访问和改变,这将导致潜在 bug。因此,当在 JavaScript 中编程时,不要忘了对变量应用 var
。
尽管 JavaScript 不够完善,但在类型方面十分简单。事实上,JavaScript 仅有 4 个基本类型,其中三个是基元。JavaScript 的基元类型是 Number
、String
、和 Boolean
。您可通过 JavaScript typeof
运算符来在操作中查看这些类型。
我们来一起看一下该问题。在 Chrome's JavaScript 中,输入清单 2 中的内容:
var string = "test" typeof string |
可以看到控制台输出值 “string
”。还要注意在 JavaScript 中分号是可选的。正如在流行的语言当中一样,string
通过引号来划定;因此,数字通过数字来划定。Booleans 通过值 true 或者 false 来划定,没有分号。
清单 3. JavaScript truth 与 numbers
var aNumber = 10 var anotherNumber = 0.99 var aBool = true var notABoolean = "false" |
您会注意到,JavaScript 不区分数字类型;数字就是数字,只不过具有不同格式。
JavaScript 还支持通用对象,它本身具有实例类型,比如 Array
,如清单 4 所示:
> var myArray = ["Hello", 1, true] > typeof myArray "object" > myArray instanceof Array true |
JavaScript 中的 Array
s 更像其他语言中的列表:可不必限制大小来进行创建,可以保存任何您输入的内容。比如在 Ruby 或者 Groovy 中,JavaScript Array
s 可通过文字语法来创建:[]
。更重要的是,就像在其他支持列表的语言一样,希望在 JavaScript Array
s 支持方法(如清单 5 所示):
> var myArray = ["Hello", 1, true] > myArray[0] "Hello" > myArray.length 3 > myArray.pop() true > myArray ["Hello", 1] > myArray.pop() 1 > myArray ["Hello"] > myArray.push("pushed") 2 > myArray ["Hello", "pushed"] |
可通过 Array
的位置来获取其值,从零开始。Array
s 支持push
和 pop
操作,其中 push
增加项目(在其最后一个位置)而 pop
移除项目(就像堆栈,从最后一个开始)。
Array
s 还支持迭代,如清单 6 所示:
> var myArray = [1,2] > for(var i = 0; i < myArray.length; i++) { console.log(myArray[i]) } 1 2 |
JavaScript 不仅是一个弱类型的语言 — 它比 Ruby 或者 Groovy 更弱 !JavaScript 可强制变量在代码的特定位置为任何类型。这符合 JavaScript 最初设想:Web 页面交互。JavaScript 不应草率地禁止用户读取在线文章!
类型强制不仅限于 JavaScript,但是 JavaScript 的特点是非常灵活。这是好事还是坏事,取决于您怎么看。JavaScript 的松散可能会隐藏缺陷,就像全局变量一样。
例如,先定义 Array
然后无意中尝试用于进行一些数字操作,甚至是一些 String
级联,如清单 7 所示:
> var myArray = [1,2] > console.log(2 * myArray) > console.log("A" + myArray) |
在本例中,第一个日志消息将会打印 NaN
,而第二个将会打印 A1,2
。在两个例子中,该代码能 “正常运行”,因为没有任何错误发生 — JavaScript 只是不停地运转。这是极端情况下的弱类型。Ruby 中同样的代码不会这样运行,如清单 8 所示:
> array = ["A", "B"] > ans = 2 * array |
清单 8 中的 Ruby 代码将会出错:
TypeError: Array can't be coerced into Fixnum |
如果尝试向 array
增加 "A"
,情况将是:
TypeError: can't convert Array into String |
如果在 Groovy 中尝试相同的操作,将会得到如下结果:
groovy.lang.MissingMethodException: No signature of method: java.lang.Integer.plus() is applicable for argument types: (java.util.ArrayList) values: [[A, B]] |
因此,您可以在操作中看到不同层面的弱类型。显而易见,如果有一个度量类型强弱的标准,JavaScript 将会是它们当中最弱的!
JavaScript 函数,类似于 Java 方法,是用于定义和封装可重用行为的结构。JavaScript 中的函数看上去很像 Groovy 的闭包。在 JavaScript 中的函数是对象。事实上,他们是第一类对象,不像 Java 代码中的方法。因为 JavaScript 函数是对象,所以它可传递给其他函数,并可被调用。
利用 function
关键字来定义函数。就像 Java 语言中的方法声明一样,可以指定参数,还可从 JavaScript 函数返回一些内容。与动态语言不同,比如 Groovy 或者 Ruby,其中返回调用是可选的(这样任何方法的最后一行将返回),如果想要得到返回值,JavaScript 的函数中必须使用 return 语句;否则,将不会返回值。
可以像在 Groovy 中调用闭包一样来在 JavaScript 中调用函数。在清单 9 中,定义了一个没有参数的简单函数。其目的是在 Chrome 的 JavaScript 控制台中打印 “blah”。
> function blah() { console.log("blah"); } > blah() //prints blah > blah.call() //prints blah > blah.apply() //prints blah |
可通过方法 call
或者方法 apply
直接调用有括号(也就是 ()
)的函数。在这里展示了首个无类函数对象。清单 10 展示了在函数 blah
中调用 garbage 方法时的情形:
> blah.foo() |
在本例中,错误消息说明 foo
不是一个定义的方法,像这样:
TypeError: Object function blah() { console.log("blah"); } has no method 'foo' |
现在再次读取错误消息。看到 foo
不是 已定义的,这意味着如果它 被 定义,一切就会正常。
JavaScript 支持原语,我们曾讨论过。它也支持对象,比如 Array
。JavaScript 不支持类 — 至少在经典 Java 语言中不支持。因为 JavaScript 是基于原型的语言,您不能定义类:相反,通过克隆 现有对象来重用行为。因此,在 JavaScript 中,不定义类对象,而在函数中进行定义,然后利用嵌套函数来定义行为 — 有些已在运行中见过。
想要模拟一个类,您必须定义一个函数。可以给其一个名称(也就是一个类名),指定参数(和在构造函数中一样),甚至可以使用关键字 .this
,这意味着在函数范围内引用变量。更何况,内部函数可以具有别名,看上去像方法调用一样。
为了进行说明,在清单 11 中,我将创建一个 Message
原型(也称为一个类),这非常简单。我将提供一些参数(消息从何处来,发给谁,以及消息本身),而且该类将会以 JSON 格式呈现该消息。
function Message(to, from, msg){ this.to = to; this.from = from; this.msg = msg; this.asJSON = function(){ return "{'to':'" + this.to + "', 'from':'" + this.from + "', 'message':'" + this.msg + "'}"; } } |
在 清单 11 中,我定义了一个 Message
函数 — 带有一个名字和几个属性的对象;即,to
、from
、和 msg
。然后我定义了一个属性(asJSON
)指向内部函数,其任务是将 JSON 消息用字符串表示。
注意,还可在 Web 页面中定义该 “类”,利用 Chrome 来进行加载,打开 JavaScript 控制台,并交互式地进行使用。这就是清单 12 所述的:
> var message = new Message('Andy', 'Joe', 'Party tonight!'); > message.asJSON(); "{'to':'Andy', 'from':'Joe', 'message':'Party tonight!'}" |
此代码很像 Groovy 代码,甚至像 Java 代码(如果不考虑 var
),不是吗?实际上,完全可以利用 OOP 技术来构建 JavaScript 应用程序(也就是,程序包含带有数据和相互交互方法的对象)。
我希望这篇文章能够推翻早已过时的 JavaScript 语言无用论。事实上,它的功能十分强大,而且具有很多语法糖,可以像 Groovy 和 Ruby 之类新的语言一样方便。在 90 年代使得 JavaScript 流行的一些特性,在今天也是可取的。
鉴于 Web 对越来越多的 Java 应用程序开发的重要性,以及 JavaScript 作为浏览器兼容语言的独特地位,每个 Java 程序员都应当熟悉 JavaScript。 浏览器(不论是在计算机中,或者在移动设备、电话、或者平板电脑中)是越来越多用户与应用程序交互的方法。JavaScript 是所有服务器端语言中最常见的媒介。此外,对 JavaScript 有一定理解,将会使您成为任何语言领域(包括您最熟悉的语言)的一名优秀的程序员。