JavaScript中有很多內(nèi)部屬性和方法,在大多數(shù)情況下,只有JavaScript引擎才可以訪問,但不論什么都是有特例的,在這里就是指Mozilla的JavaScript引擎,包括SpiderMonkey和Rhino,都提供了若干接口來訪問這些內(nèi)部屬性,如果加以合理利用的話,不僅可以讓JavaScript更加健壯,還可以開發(fā)出一些有意思的功能,比如本文介紹的__noSuchMethod__()方法就是其中之一。
著作權(quán)聲明
本文譯自 Nicholas C. Zakas 于2009年2月17日在個(gè)人網(wǎng)站上發(fā)表的《Mozilla JavaScript extension: __noSuchMethod__》。原文是唯一的正式版,本文是經(jīng)過原作者(Nicholas C. Zakas)授權(quán)的簡(jiǎn)體中文翻譯版(Simplified Chinese Translation)。譯者(明達(dá))在翻譯的準(zhǔn)確性上做了大量的努力,并承諾譯文的內(nèi)容完全忠于原文,但可能還是包含疏漏和不妥之處,歡迎大家指正。譯注的內(nèi)容是非正式的,僅代表譯者個(gè)人觀點(diǎn)。
以下是對(duì)原文的翻譯:
和其它瀏覽器相比,Mozilla的JavaScript引擎總會(huì)有一些與眾不同的亮點(diǎn)。SpiderMonkey和他的好搭檔Rhino(用 Java實(shí)現(xiàn)的JavaScript引擎)都提供了很多擴(kuò)展特性,可以幫助我們開發(fā)更加健壯的JavaScript應(yīng)用。其中之一就是本地對(duì)象的__noSuchMethod__()方法。在大多數(shù)JavaScript引擎中,訪問一個(gè)不存在的方法時(shí)都只會(huì)簡(jiǎn)單的拋出錯(cuò)誤,而在Mozilla的引擎中,這只是默認(rèn)行為,我們可以通過覆蓋某個(gè)對(duì)象的__noSuchMethod__()方來來重新定義這個(gè)行為。當(dāng)這個(gè)對(duì)象試圖調(diào)用一個(gè)不存在的方法時(shí),就會(huì)觸發(fā)該對(duì)象的__noSuchMethod__()方法。
當(dāng)__noSuchMethod__()方法被調(diào)用時(shí),JavaScript引擎會(huì)傳入兩個(gè)參數(shù),一個(gè)是調(diào)用方法的名稱,一個(gè)是參數(shù)數(shù)組,對(duì)應(yīng)于要傳遞給調(diào)用方法的所有參數(shù),注意這個(gè)參數(shù)數(shù)組應(yīng)該是一個(gè)Array對(duì)象,而不是arguments對(duì)象,而且就算沒有參數(shù),也要傳遞一個(gè)空數(shù)組,下面舉一個(gè)簡(jiǎn)單的例子加以說明:
// 注意,下面的代碼只有在使用SpiderMonkey或者Rhino的瀏覽器中才會(huì)被正確解析 var person = { name: "Nicholas", __noSuchMethod__: function(name, args){ alert("Method called '" + name + "' executed with arguments [" + args + "]"); } }
//"Method called 'sayName' executed with arguments []" person.sayName();
//"Method called 'phone' executed with arguments [Mike]" person.phone("Mike");
這段代碼定義了一個(gè)person對(duì)象,并重寫了該對(duì)象的__noSuchMethod__()方法。當(dāng)調(diào)用person對(duì)象的sayName()方法和phone()方法時(shí),由于這兩個(gè)方法都不存在,所以__noSuchMethod__()方法會(huì)被自動(dòng)調(diào)用,這樣我們就避免了一個(gè)錯(cuò)誤的顯示,并且可以做出相應(yīng)的處理。在上面這個(gè)例子中,我們所做的處理就是直接將方法的名稱和傳遞的參數(shù)直接顯示出來。
但話說回來,在運(yùn)行時(shí)才發(fā)現(xiàn)未定義方法的情況,是不該出現(xiàn)在正常的開發(fā)實(shí)踐中的,那簡(jiǎn)直就是自取煩惱。對(duì)于通常的情況來說,這個(gè)方法似乎沒有什么作用,但他確實(shí)為我們提供了一個(gè)可能性,來創(chuàng)建一些有趣的動(dòng)態(tài)工具,比如說建立一個(gè)可以輸出有效XHTML文檔的對(duì)象:
function HTMLWriter(){ this._work = []; }
HTMLWriter.prototype = {
escape: function (text){ return text.replace(/[><"&]/g, function(c){ switch(c){ case ">": return ">"; case "<": return "<"; case "\"": return """; case "&": return "&"; } }); },
startTag: function(tagName, attributes){ this._work.push("<" + tagName);
if (attributes){ var name, value; for (name in attributes){ if (attributes.hasOwnProperty(name)){ value = this.escape(attributes[name]); this._work.push(" " + name + "=\"" + value + "\""); } } }
this._work.push(">"); },
text: function(text){ this._work.push(this.escape(text)); },
endTag: function(tagName){ this._work.push(""); },
toString: function(){ return this._work.join(""); }
};
var writer = new HTMLWriter(); writer.startTag("html"); writer.startTag("head"); writer.startTag("title"); writer.text("Example & Test"); writer.endTag("title"); writer.endTag("head"); writer.startTag("body", { style: "background-color: red" }); writer.text("Hello world!"); writer.endTag("body"); writer.endTag("html");
alert(writer);
這段代碼通過三個(gè)方法來完成任務(wù),分別是:startTag()、endTag()和text()。而上面給出的調(diào)用例子,卻顯得非常冗長。想象一下,如果不使用startTag()、endTag()和text()這三個(gè)方法,而是為每一個(gè)有效的XHTML標(biāo)記都建立一個(gè)方法,那么這個(gè)例子的調(diào)用方法可能就會(huì)變成下面這個(gè)樣子了:
var writer = new HTMLWriter(); var result = writer.html() .head().title().text("Example & Test").xtitle().xhead() .body().text("Hell world!").xbody() .xhtml().toString();
由于每個(gè)標(biāo)簽的實(shí)現(xiàn)大致相同,所以我們可能需要為HTMLWriter對(duì)象復(fù)制一系列非常相似的方法,這無疑是一種嚴(yán)重的浪費(fèi)行為。而這正是__noSuchMethod__()發(fā)揮真正作用的時(shí)候。讓我們來看看用__noSuchMethod__()來實(shí)現(xiàn)這種效果到底有多么簡(jiǎn)單:
function HTMLWriter(){ this._work = []; }
HTMLWriter.prototype = {
escape: function (text){ return text.replace(/[><"&]/g, function(c){ switch(c){ case ">": return ">"; case "<": return "<"; case "\"": return """; case "&": return "&"; } }); },
text: function(text){ this._work.push(this.escape(text)); return this; },
toString: function(){ return this._work.join(""); },
__noSuchMethod__: function(name, args){ var tags = [ "a", "abbr", "acronym", "address", "applet", "area", "b", "base", "basefont", "bdo", "big", "blockquote", "body", "br", "button", "caption", "center", "cite", "code", "col", "colgroup", "dd", "del", "dir", "div", "dfn", "dl", "dt", "em", "fieldset", "font", "form", "frame", "frameset", "h1", "h2", "h3", "h4", "h5", "h6", "head", "hr", "html", "i", "iframe", "img", "input", "ins", "isindex", "kbd", "label", "legend", "li", "link", "map", "menu", "meta", "noframes", "noscript", "object", "ol", "optgroup", "option", "p", "param", "pre", "q", "s", "samp", "script", "select", "small", "span", "strike", "strong", "style", "sub", "sup", "table", "tbody", "td", "textarea", "tfoot", "th", "thead", "title", "tr", "tt", "u", "ul", "var" ];
var closeTag = (name.charAt(0) == "x"), tagName = closeTag ? name.substring(1) : name;
if (tags.indexOf(tagName) > -1){ if (!closeTag){ this._work.push("<" + tagName);
if (args.length){ var attributes = args[0], name, value; for (name in attributes){ if (attributes.hasOwnProperty(name)){ value = this.escape(attributes[name]); this._work.push(" " + name + "=\"" + value + "\""); } } }
this._work.push(">"); } else { this._work.push(""); } return this; } else { throw new Error("Method '" + name + "' is undefined."); }
}
};
這段代碼的主要功能都是在__noSuchMethod__()中實(shí)現(xiàn)的。它包含一個(gè)數(shù)組,對(duì)應(yīng)于全部有效的XHTML標(biāo)簽,用于查找可以調(diào)用的方法。如果需要關(guān)閉標(biāo)簽,只需要在方法名前面加一個(gè)“x”就可以,在__noSuchMethod__()中,會(huì)對(duì)方法名的首字母進(jìn)行判斷,如果首字母是“x”,就會(huì)標(biāo)記為結(jié)束標(biāo)簽,并將“x”從方法名稱中去掉。接下來,會(huì)通過Mozilla的數(shù)組擴(kuò)展 indexOf()來判斷方法名稱是否在可用標(biāo)簽的數(shù)組里面,如果方法名是無效的,就會(huì)拋出一個(gè)錯(cuò)誤;如果方法名是有效的,就會(huì)返回生成的標(biāo)簽字符串。代碼所支持的標(biāo)簽數(shù)量是可以動(dòng)態(tài)設(shè)置的,我們只需要對(duì)標(biāo)簽列表數(shù)組進(jìn)行修改,就可以達(dá)到添加或者刪除“方法”的目的。
很顯然,由于這個(gè)特性不能跨瀏覽器,所以肯定不能用于通常的情況下。但對(duì)于那些專門針對(duì)Mozilla引擎(比如Firefox等)的JavaScript應(yīng)用來說,這無疑為我們敞開了一道神奇的大門,尤其在開發(fā)動(dòng)態(tài)接口時(shí),__noSuchMethod__()將是一個(gè)非常強(qiáng)有力的工具。
本文鏈接:http://www.95time.cn/tech/web/2009/6531.asp
出處:七月佑安
責(zé)任編輯:bluehearts
◎進(jìn)入論壇網(wǎng)頁制作、WEB標(biāo)準(zhǔn)化版塊參加討論,我還想發(fā)表評(píng)論。
|