在 20 世紀 90 年代,也就是早期的 WEB 站點上,所有的網(wǎng)頁內(nèi)容都是靜態(tài)的,所謂靜態(tài)是指,除了點擊超鏈接,你無法通過任何方式同頁面進行交互,比如讓頁面元素接受事件,修改字體等。人們于是迫切的需要一種方式來打破這個局限,于是到了 1996 年,網(wǎng)景 (Netscape) 公司開始研發(fā)一種新的語言Mocha,并將其嵌入到自己的瀏覽器 Netscape 中,這種語言可以通過操縱 DOM(Document Object Model,文檔對象模型)來修改頁面,并加入了對鼠標事件的支持。Mocha使用了C的語法,但是設計思想上主要從函數(shù)式語言 Scheme 那里取得了靈感。當Netscape 2 發(fā)布的時候,Mocha被改名為LiveScript,當時可能是想讓 LiveScript 為 WEB 頁面注入更多的活力。后來,考慮到這個腳本語言的推廣,網(wǎng)景采取了一種宣傳策略,將 LiveScript更名為 JavaScript,目的是為了跟當時非常流行的面向?qū)ο笳Z言 Java 發(fā)生曖昧的關(guān)系。這種策略顯然頗具成效,以至于到現(xiàn)在很多初學者還會為 JavaScript 和 Java 的關(guān)系而感到困惑。
Javascript 取得成功了之后,確實為頁面注入了活力,微軟也緊接著開發(fā)自己的瀏覽器腳本語言,一個是基于 BASIC 語言的 VBScript,另一個是跟 Javascript 非常類似的 Jscript,但是由于 Javascript 已經(jīng)深入人心,所以在隨后的版本中,微軟的 IE 幾乎是將 Javascript 作為一個標準來實現(xiàn)。當然,兩者仍然有不兼容的地方。1996 年后期,網(wǎng)景向歐洲電腦廠商協(xié)會(ECMA)提交了Javascript的設計,以申請標準化,ECMA 去掉了其中的一些實現(xiàn),并提出了ECMAScript-262標準,并確定 Javascript 的正式名字為 ECMAScript,但是 JavaScript 的名字已經(jīng)深入人心,故本書中仍沿用 Javascript 這個名字。
WEB頁面在剛開始的時候,是不能動態(tài)修改其內(nèi)容的,要改變一個頁面的內(nèi)容,需要先對網(wǎng)站上的靜態(tài)HTML文件進行修改,然后需要刷新瀏覽器。后來出現(xiàn)的JSP,ASP等服務器端語言可以為頁面提供動態(tài)的內(nèi)容,但是如果沒有JavaScript則無法在服務器返回之后動態(tài)的在前端修改頁面,也無法有諸如鼠標移上某頁面元素則高亮該元素之類的效果,因此JavaScript的出現(xiàn)大大的豐富了頁面的表現(xiàn),提高了用戶體驗。
而當 AJAX 流行起來之后,更多的非常絢麗的 WEB 應用涌現(xiàn)了,而且呈越來越多的趨勢,如 Gmail,Google Map,Google Reader,Remember the milk,facebook 等等優(yōu)秀的 WEB2.0 應用,都大量的使用了 JavaScript 及其衍生的技術(shù) AJAX。
JavaScript 是一門動態(tài)的,弱類型,基于原型的腳本語言。在 JavaScript 中“一切皆對象”,在這一方面,它比其他的 OO 語言來的更為徹底,即使作為代碼本身載體的 function,也是對象,數(shù)據(jù)與代碼的界限在 JavaScript 中已經(jīng)相當模糊。雖然它被廣泛的應用在 WEB 客戶端,但是其應用范圍遠遠未局限于此。下面就這幾個特點分別介紹:
動態(tài)性是指,在一個 Javascript 對象中,要為一個屬性賦值,我們不必事先創(chuàng)建一個字段,只需要在使用的時候做賦值操作即可,如下例:
Js 代碼
//定義一個對象
var obj = new Object();
//動態(tài)創(chuàng)建屬性name
obj.name = "an object";
//動態(tài)創(chuàng)建屬性sayHi
obj.sayHi = function(){
return "Hi";
}
obj.sayHi();
加入我們使用 Java 語言,代碼可能會是這樣:
Js 代碼
class Obj{
String name;
Function sayHi;
public Obj(Sting name, Function sayHi){
this.name = name;
this.sayHi = sayHi;
}
}
Obj obj = new Obj("an object", new Function());
動態(tài)性是非常有用的,這個我們在第三章會詳細講解。
與 Java,C/C++不同,Javascript 是弱類型的,它的數(shù)據(jù)類型無需在聲明時指定,解釋器會根據(jù)上下文對變量進行實例化,比如:
Js代碼
//定義一個變量s,并賦值為字符串
var s = "text";
print(s);
//賦值s為整型
s = 12+5;
print(s);
//賦值s為浮點型
s = 6.3;
print(s);
//賦值s為一個對象
s = new Object();
s.name = "object";
print(s.name);
結(jié)果為:
text
17
6.3
Object
可見,Javascript 的變量更像是一個容器,類似與 Java 語言中的頂層對象 Object,它可以是任何類型,解釋器會根據(jù)上下文自動對其造型。
弱類型的好處在于,一個變量可以很大程度的進行復用,比如 String 類型的 name 字段,在被使用后,可以賦值為另一個 Number 型的對象,而無需重新創(chuàng)建一個新的變量。不過,弱類型也有其不利的一面,比如在開發(fā)面向?qū)ο蟮?Javascript 的時候,沒有類型的判斷將會是比較麻煩的問題,不過我們可以通過別的途徑來解決此問題。
通常來說,Javascript 是一門解釋型的語言,特別是在瀏覽器中的 Javascript,所有的主流瀏覽器都將Javascript 作為一個解釋型的腳本來進行解析,然而,這并非定則,在 Java 版的 Javascript 解釋器 rhino 中,腳本是可以被編譯為 Java 字節(jié)碼的。
解釋型的語言有一定的好處,即可以隨時修改代碼,無需編譯,刷新頁面即可重新解釋,可以實時看到程序的結(jié)果,但是由于每一次都需要解釋,程序的開銷較大;而編譯型的語言則僅需要編譯一次,每次都運行編譯過的代碼即可,但是又喪失了動態(tài)性。
當 Javascript 第一次出現(xiàn)的時候,是為了給頁面帶來更多的動態(tài),使得用戶可以與頁面進行交互為目的的,雖然Javascript 在 WEB 客戶端取得了很大的成功,但是 ECMA 標準并沒有局限其應用范圍。事實上,現(xiàn)在的 Javascript 大多運行與客戶端,但是仍有部分運行于服務器端,如 Servlet,ASP 等,當然,Javascript 作為一個獨立的語言,同樣可以運行在其他的應用程序中,比如 Java 版的 JavaScript 引擎 Rhino,C 語言版的 SpiderMonkey 等,使用這些引擎,可以將 JavaScript 應用在任何應用之中。
客戶端的 JavaScript 隨著 AJAX 技術(shù)的復興,越來越凸顯了 Javascript 的特點,也有越來越多的開發(fā)人員開始進行 JavaScript 的學習,使用 Javascript,你可以使你的 WEB 頁面更加生動,通過 AJAX,無刷新的更新頁面內(nèi)容,可以大大的提高用戶體驗,隨著大量的 JavaScript 包如 jQuery, ExtJS,Mootools 等的涌現(xiàn),越來越多的絢麗,高體驗的 WEB 應用被開發(fā)出來,這些都離不來幕后的 JavaScript 的支持。
http://wiki.jikexueyuan.com/project/javascript-core/images/js1.png" alt="" />
瀏覽器中的 JavaScript 引擎也進行了長足的發(fā)展,比如 FireFox 3,當時一個宣傳的重點就是速度比 IE 要快,這個速度一方面體現(xiàn)在頁面渲染上,另一方面則體現(xiàn)在 JavaScript 引擎上,而 Google 的 Chrome 的JavaScript 引擎 V8 更是將速度發(fā)展到了極致。很難想象,如果沒有 JavaScript,如今的大量的網(wǎng)站和WEB應用會成為什么樣子。
我們可以看幾個例子,來說明客戶端的 JavaScript 的應用程度:
http://wiki.jikexueyuan.com/project/javascript-core/images/js2.png" alt="" />
圖 ExtJS 實現(xiàn)的一個網(wǎng)絡相冊,ExtJS 是一個非常優(yōu)秀的 JavaScriipt 庫
http://wiki.jikexueyuan.com/project/javascript-core/images/js3.png" alt="" />
圖 ExtJS 實現(xiàn)的一個表格,具有排序,編輯等功能
當然,客戶端的 JavaScript 各有側(cè)重,jQuery 以功能見長,通過選擇器,可以完成 80% 的頁面開發(fā)工作,并且提供強大的插件機制,下圖為 jQuery 的 UI 插件:
http://wiki.jikexueyuan.com/project/javascript-core/images/js4.png" alt="" />
總之,隨著 Ajax 的復興,客戶端的 JavaScript 得到了很大的發(fā)展,網(wǎng)絡上流行著大量的優(yōu)秀的 JavaScript 庫,現(xiàn)在有一個感性的認識即可,我們在后邊的章節(jié)會擇其尤要者進行詳細講解。
相對客戶端而言,服務器端的 JavaScript 相對平淡很多,但是隨著 JavaScript 被更多人重視,JavaScript 在服務器端也開始迅速的發(fā)展起來,Helma, Apache Sling 等等。在服務器端的 JavaScript 比客戶端少了許多限制,如本地文件的訪問,網(wǎng)絡,數(shù)據(jù)庫等。
一個比較有意思的服務端 JavaScript 的例子是 Aptana 的 Jaxer,Jaxer 是一個服務器端的 Ajax 框架,我們可以看這樣一個例子(例子來源于 jQuery 的設計與實現(xiàn)這 John Resig):
<html>
<head>
<script src="http://code.jquery.com/jquery.js" runat="both"></script>
<script>
jQuery(function($){
$("form").submit(function(){
save( $("textarea").val() );
return false;
});
});
</script>
<script runat="server">
function save( text ){
Jaxer.File.write("tmp.txt", text);
}
save.proxy = true;
function load(){
$("textarea").val(
Jaxer.File.exists("tmp.txt") ? Jaxer.File.read("tmp.txt") : "");
}
</script>
</head>
<body onserverload="load()">
<form action="" method="post">
<textarea></textarea>
<input type="submit"/>
</form>
</body>
</html>
runat 屬性說明腳本運行在客戶端還是服務器端,client 表示運行在客戶端,server 表示運行在服務器端,而 both 表示可以運行在客戶端和服務器端,這個腳本可以訪問文件,并將文件加載到一個 textarea 的 DOM 元素中,還可以將 textarea 的內(nèi)容通過 Form 表單提交給服務器并保存。
再來看另一個例子,通過 Jaxer 對數(shù)據(jù)庫進行訪問:
<script runat="server">
var rs = Jaxer.DB.execute("SELECT * FROM table");
var field = rs.rows[0].field;
</script>
通過動態(tài),靈活的語法,再加上對原生的資源(如數(shù)據(jù)庫,文件,網(wǎng)絡等)操作的支持,服務器端的 JavaScript 應用將會越來越廣泛。
當 Google 的 JavaScript 引擎 V8 出現(xiàn)以后,有很多基于 V8 引擎的應用也出現(xiàn)了,其中最著名,最有前景的當算 Node.js 了,下面我們來看一下 Node.js 的例子:
var sys = require('sys'),
http = require('http');
http.createServer(function (req, res) {
setTimeout(function () {
res.sendHeader(200, {'Content-Type': 'text/plain'});
res.sendBody('Hello World');
res.finish();
}, 2000);
}).listen(8000);
sys.puts('Server running at http://127.0.0.1:8000/');
保存這個腳本為 sayHello.js,然后運行:
node sayHello.js
程序?qū)诳刂婆_上打?。?/p>
Server running at http://127.0.0.1:8000/
訪問 http://127.0.0.1:8000,兩秒鐘之后頁面會響應:Hello, World。
再來看另一個官方提供的例子:
var tcp = require('tcp');
var server = tcp.createServer(function (socket) {
socket.setEncoding("utf8");
socket.addListener("connect", function () {
socket.send("hello\r\n");
});
socket.addListener("receive", function (data) {
socket.send(data);
});
socket.addListener("eof", function () {
socket.send("goodbye\r\n");
socket.close();
});
});
server.listen(7000, "localhost");
訪問 localhost 的 7000 端口,將建立一個 TCP 連接,編碼方式為 utf-8,當客戶端連接到來時,程序在控制臺上打印
hello
當接收到新的數(shù)據(jù)時,會將接收到的數(shù)據(jù)原樣返回給客戶端,如果客戶端斷開連接,則向控制臺打?。?/p>
goodbay
Node 提供了豐富的 API 來簡化服務器端的網(wǎng)絡編程,由于 Node 是基于一個 JavaScript 引擎的,因此天生的就具有動態(tài)性和可擴展性,因此在開發(fā)網(wǎng)絡程序上,確實是一個不錯的選擇。
通過使用 JavaScript 的引擎的獨立實現(xiàn),比如 Rhino,SpliderMonkey,V8 等,可以將 JavaScript 應用到幾乎所有的領域,比如應用程序的插件機制,高級的配置文件分析,用戶可定制功能的應用,以及一些類似與瀏覽器場景的比如 Mozilla 的 ThunderBrid,Mozilla 的 UI 框架 XUL,筆者開發(fā)的一個 Todo 管理器 sTodo 等。
http://wiki.jikexueyuan.com/project/javascript-core/images/js5.png" alt="" />
圖 sTodo 一個使用 JavaScript 來提供插件機制的 Java 桌面應用
Java 版的 JavaScript 引擎原生的可以通過使用 Java 對象,那樣將會大大提高 JavaScript 的應用范圍,如數(shù)據(jù)庫操作,服務器內(nèi)部數(shù)據(jù)處理等。當然,JavaScript這種動態(tài)語言,在UI方面的應用最為廣泛。
著名的 Adobe reader 也支持 JavaScript 擴展,并提供 JavaScript 的 API 來訪問 PDF 文檔內(nèi)容,可以通過 JavaScript 來定制 Adobe Reader 的界面以及功能等。
app.addMenuItem({
cName: "-",
// menu divider
cParent: "View",
// append to the View menu
cExec: "void(0);"
});
app.addMenuItem({
cName: "Bookmark This Page &5",
cParent: "View",
cExec: "AddBookmark();",
cEnable: "event.rc= (event.target != null);"
});
app.addMenuItem({
cName: "Go To Bookmark &6",
cParent: "View",
cExec: "ShowBookmarks();",
cEnable: "event.rc= (event.target != null);"
});
app.addMenuItem({
cName: "Remove a Bookmark",
cParent: "View",
cExec: "DropBookmark();",
cEnable: "event.rc= (event.target != null);"
});
app.addMenuItem({
cName: "Clear Bookmarks",
cParent: "View",
cExec: "ClearBookmarks();",
cEnable: "event.rc= true;"
});
為 Adobe Reader 添加了 4 個菜單項,如圖:
http://wiki.jikexueyuan.com/project/javascript-core/images/js6.png" alt="" />
另一個比較有意思的 JavaScript 實例為一個在線的遺傳算法的演示,給定一個圖片,然后將一些多邊形(各種顏色)拼成一個圖片,拼圖的規(guī)則為使用遺傳算法,使得這些多變形組成的圖片與目標圖片最為相似:
http://wiki.jikexueyuan.com/project/javascript-core/images/js7.png" alt="" />
可見,JavaScript 在其他方面的也得到了廣泛的應用。