标题:Mozilla浏览器中特殊的Javascript方法——__noSuchMethod__()
翻译:枫行天下 http://www.msphome.cn/
原作者:Nicholas C. Zakas
原标题:Mozilla JavaScript extension: __noSuchMethod__
发表时间:2009年2月17日
原文地址:http://www.nczonline.net/blog/2009/02/17/mozilla-javascript-extension-nosuchmethod/
Mozilla的Javascript引擎经常与其他公司的产品有那么一点不同。SpiderMonkey和它的Java接口Rhino,都预留了一些对象的内建方法。在绝大多数的Javascript引擎中,调用一个方法出错都不会返回一个简单的结果;在Mozilla的引擎中,这只是一个默认行为,你可以在这个对象内定义一个__noSuchMethod__()方法忽略这个行为。这个方法(__noSuchMethod__())将会在调用一个不存在的方法出错时被自动调用。
当__noSuchMethod__()被调用时,将会收到两个参数,一个是调用的方法名,另一个是参数列表组成的数组。需要注意的是,这个数组是一个实例数组【instance of Array (not an arguments object) 】,在没有参数的时候也存在这个数组,以下是一个简单的例子:
javascript 代码
- var person = {
- name: "Nicholas",
- __noSuchMethod__: function(name, args){
- alert("Method called ‘" + name +
- "’ executed with arguments [" + args + "]");
- }
- }
- person.sayName();
- person.phone("Mike");
这段代码定义了一个 person 变量,包含一个__noSuchMethod__() 方法。当对象的方法sayName() 和 phone()被调用的时候,__noSuchMethod__()就会被自动执行,以阻止错误的产生,并且继续运行代码。在这个例子中,我们只是显示了方法名和参数列表。
当然,一段正常的程序在运行时一般不会出现调用不存在的方法;这时你有点迷惑了,这并没有什么意义。但是,在一些动态执行的内容中这一点就显得十分必要了。建立一个对象,帮助输出验证的xhtml:
javascript 代码
- 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);
这段代码使用了 startTag(), endTag()和 text()三个方法来完成工作。用法有点啰嗦。想象一下如果使用startTag() 和 endTag()两个方法来枚举xhtml标签,你的代码可能是这样:
javascript 代码
- var writer = new HTMLWriter();
- var result = writer.html()
- .head().title().text("Example & Test").xtitle().xhead()
- .body().text("Hell world!").xbody()
- .xhtml().toString();
既然所有的行为多多少少有点相似,那么费力气在这个对象里面建立这么多相同的方法,实在是增加了冗码。现在,我们可以看出__noSuchMethod__()方法的威力了。看下面如此简单的代码来完成同样的工作:
javascript 代码
- 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()函数被用来从已知标签列表中执行匹配。如果标签名不存在,错误就会被抛出;另一方面,正常的进程将会被执行。这样,只需变换支持的标签,相应的“方法”就会被创建或者删除。
显然,这不是用在通用版【regular basis】上的,不支持跨浏览器。但这为在一些基于Mozilla脚本解析引擎的浏览器(例如Firefox或者其他)上开发提供了新的思路。 __noSuchMethod__()方法在动态Javascript界面开发中,是一个相当有用的方法。
PS:第一次翻译外文资料,练习练习英语。翻译的难免有错误,还请大家批评指出。