新規格的制定是一個漫長而痛苦的過程,ECMA-262 Edition 3規格是1999年制定的,恐怕當初誰也沒想到下一版竟然搞了十年!但是這個語言真的深入了解的人不夠多,早期也沒有像jQuery這些經典的Library出現,所以到現在才拍板也是可以想像的,可惜的是像Adobe這樣非常早就把早期的Edition 4規格納入ActionScript中的廠商,結果Edition 4難產,而在Edition 5中,許多原來在Edition 4中有的東西也沒放進去...
所以,ECMA-262 Edition 5裡面,還是沒有class, interface, import, extends, package, implements, private, protected, public... (但是,許多用class可以做到的事情,即使沒這些也不是做不到)
Javascript的發明人,也是Mozilla的CTO-Brendan Eich,曾經在TC39一次會議後,寫信感謝Douglas Crockford助拳,說他好像Yoda大師,好像Gandolf(還搞了一副圖片:Douglas Crockford在橋上對著ES4 Log說: "You shall not pass...",背後是JS大眾)。可見戰況激烈:Harmony...這時這一版還是叫做Harmony,後來變成Edition3.1,最後變成Edition 5。(感想:魔戒跟星際大戰果然是西方經典,不過果然Eich比較年輕,Crockford是形容場面好像十二怒漢)
不談八卦了,而且TC39中的兩派也妥協了,所以ECMA-262 Edition 5才能在年底正式發布,還是來瞧瞧有什麼有趣的東西吧。
以下分享的內容,主要是摘錄及整理自John Resig部落格中的兩篇文章:ECMAScript 5 Objects and Properties及ECMAScript 5 Strict Mode, JSON, and More;以及Mozilla網站上關於Javascript1.7 / 1.8的說明,還有規格書草案。
JSON
新增的最重要功能之一,就是JSON相關功能。其實Object Literal跟Array Literal在ECMA-262 Edition 3裡面就有,JSON主要也就是由這一部份的功能發展出來的。新規格中的JSON部份,主要是Javascript中的物件與陣列要如何轉換成JSON字串,以及如何從JSON字串轉換為物件與陣列。還沒試過其他瀏覽器,不過從Firefox 3.5開始(沒記錯的話,可能是更新的版本),就內建原生的JSON支援。其他瀏覽器如果還沒支援的話,也可以到http://json.org下載函式庫來用。(這個網站也是Douglas Crockford維護的,其實Object/Array Literal作為一種資料傳遞的格式,也就是JSON,也是他提倡的。)
嚴格模式
在任何context中用"use strict;"便可讓這個context進入嚴格模式。在嚴格模式中,對於物件的操作會有更多限制:
1.不能使用delete刪除變數與函數
2.不能使用eval
3.不能使用with
4.物件不可有同名的屬性
5.不能用覆寫函數的arguments物件
6.無法使用arguments.callee與arguments.caller(所以在匿名函數中無法使用arguments.callee來參考到自己了,所以在許多使用狀況下必須為函數取名)
7.不能取得其他context中函數的caller與arguments物件,例如:
function outer() {
function inner() {
var a = outer.caller
}
}
8.函數.call(null)會產生錯誤,而不是在global context中執行
物件與property
物件property不再只是與物件相聯繫的值,可以對他做更詳細的設定來定義他的特性,例如是否可寫入(writable)、是否可設定(configurable)、是否可列舉(enumerable)等。不可寫入的話,property就成為唯讀的;不可設定的話,property就無法刪除,也無法重新設定他的特性;不可列舉的話,使用for...in就不會被列舉出來。
定義物件時,可以使用descriptor來詳細設定他的特性,例如(這樣叫做Data Descriptor):
var a = {};
Object.defineProperties(a, {
'name' : {
value: 'fillano',
writable: false,
enumerable: false,
configurable: false
},
'age' : {
value: 30,
writable: true,
enumerable: true,
configurable: false
}
});
另外,也可以定義property的getter與setter(這樣叫做Accessor Descriptor):
var a = {};
(function(){
var name = 'fillano';
Object.defineProperties(a, {
'name' : {
get: function(){return name;},
set: function(a) {name = a;},
writable: true,
enumerable: true,
configurable: false
}
});
})();
相較以前,功能更為強大。透過getter與setter,現在真正有了一些把property抽象的方法,而且可以在access的過程中加以攔截。
為了管理物件,Object及Object.prototype新增了許多方法,詳細的還是看一下規格。例如使用Object.keys()、Object.getOwnPropertyNames()可以產生並返回一個陣列,內含物件所有可列舉的property name等等。底下就把一些相關方法列舉一下:
(以下我使用OwnedProperty來稱呼物件非繼承來的property)
Object物件多了許多管理用的「靜態」方法:
1.Object.getPrototypeOf ( O ):取得物件的prototype
2.Object.getOwnPropertyDescriptor ( O, P ):取得物件本身OwnedProperty的descriptor(不可是繼承的,這樣會回傳undefined)
3.Object.getOwnPropertyNames ( O ):取得物件本身所有可列舉的,OwnedProperties名稱陣列
4.Object.create ( O [, Properties] ):產生一個物件,並且用descriptor定義他的OwnedProperties
5.Object.defineProperty ( O, P, Attributes ):用descriptor定義一個property
6.Object.defineProperties ( O, Properties ):用descriptor定義多個properties
7.Object.seal ( O ):把物件的每個OwnedProperty的configurable屬性設為false,同時把物件的extensible內部屬性設為false,這樣就不能動態新增property,也不能刪除或修改已有OwnedProperty的屬性
8.Object.freeze ( O ):除了seal操作,另外讓所有OwnedProperty的writable屬性設為false
9.Object.preventExtensions ( O ):把物件的extensible內部屬性設為false,這樣就不能動態新增Properties
10.Object.isSealed ( O ):判斷物件是否被seal
11.Object.isFrozen ( O ):判斷物件是否被freeze
12.Object.isExtensible ( O ):判斷物件是否被preventExtensions
13.Object.keys ( O ):取得所有properties名稱陣列,並且與使用for...in取得的順序相同
透過這一些方法,即使是用戶自己產生的物件,也可以做保護,增加一些程式的安全性與可維護性。這樣的安全性以往要透過ADSafe這一類的沙箱技術才可能做到(不然就得靠瀏覽器的安全能力)。
(待續)