Mozilla JavaScript 擴展:__noSuchMethod__
Mozilla 的 JavaScript 引擎一直與其他公司的引擎有些不同。 SpiderMonkey 及其 Java 端口 Rhino 長期以來一直包含旨在使 JavaScript 更健壯的額外功能。 __noSuchMethod__()
就是其中一項功能 本機對像上可用的方法。在大多數 JavaScript 引擎中,調用不存在的方法只會導致錯誤;在 Mozilla 引擎中,這只是默認行為。您可以通過定義 __noSuchMethod__()
來覆蓋該行為 對像上的方法。每當在對像上調用未定義的方法時,都會執行此方法。
調用時,__noSuchMethod__()
方法接收兩個參數:被調用的方法的名稱和傳遞給該方法的參數數組。請注意,參數數組是 Array
的一個實例 (不是 arguments
object) 並且即使沒有參數也總是被傳遞。一個簡單的例子:
//Works in Mozilla JavaScript engines only!
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");
這段代碼定義了一個變量person
帶有 __noSuchMethod__()
方法定義。當方法 sayName()
和 phone()
在對像上調用,__noSuchMethod__()
而是調用方法,以防止錯誤並允許其他處理。在這種情況下,我只是顯示方法的名稱和傳入的參數。
當然,正常的編程實踐不會涉及到運行時才知道的方法。那隻會令人困惑。這不是您甚至不想定期做的事情。然而,它確實為動態實用程序開闢了一些有趣的可能性。考慮創建一個有助於輸出有效 XHTML 的對象:
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("<!--" + tagName + "-->");
},
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);
此代碼使用三種方法完成這項工作:startTag()
, endTag()
, 和 text()
.用法有點冗長。想像一下,如果不使用 startTag()
和 endTag()
,每個有效的 XHTML 標記都有一個方法。您的用法可能如下所示:
var writer = new HTMLWriter();
var result = writer.html()
.head().title().text("Example & Test").xtitle().xhead()
.body().text("Hell world!").xbody()
.xhtml().toString();
由於所有標籤的行為或多或少都相同,因此您將被迫在 HTMLWriter
上創建相當於復制方法的內容 對象,這是非常浪費的。這就是 __noSuchMethod__()
的真正威力所在 進來。看看這樣的實現代碼變得多麼簡單:
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__()
中完成 .它包含所有有效 XHTML 標記的數組,用於查找被調用的方法。由於關閉標籤需要在方法的前面有一個“x”,因此會檢查這是否是第一個字符。如果是這樣,那麼 closeTag
標誌已設置,並且在繼續之前將“x”從標籤名稱中剝離。接下來,Mozilla數組擴展indexOf()
用於確定標籤名稱是否與已知列表匹配。如果標籤名無效,則拋出錯誤;否則,進行正常處理。支持的標籤數量是完全動態的,只需修改標籤列表即可添加或刪除新的“方法”。
顯然,這不是可以定期使用的東西,因為它不是跨瀏覽器。但是,如果您在 Firefox 或其他地方通過 Mozilla 引擎運行 JavaScript,它確實為一些興趣可能性打開了大門。 __noSuchMethod__()
方法是開發動態 JavaScript 接口的強大盟友。
翻譯
- 簡體中文