当前位置: 首页 > 图文教程 > 网络编程 > Javascript > Mozilla的JavaScript引擎__noSuchMethod__()方法

Javascript
jQuery代码:jQuery控制表单里的回车键
用DIV完美模拟createPopup 弹出窗口(脚本之家修正版),支持Firefox,ie,chrome
jQuery Flash/MP3/Video多媒体插件
9个JavaScript评级/投票插件
JS实现的radio图片选择按钮效果
IE中checkbox在刷新后初始化的问题
JavaScript 学习笔记(十一)
JS 对象介绍
javascript 哈希表(hashtable)的简单实现
jquery 防止表单重复提交代码
js parsefloat parseint 转换函数
javascript parseInt与Number函数的区别
JavaScript 学习笔记(十二) dom
JavaScript 学习笔记(十三)Dom创建表格
javascript 实现自由落体的方块效果
javascript 获取url参数和script标签中获取url参数函数代码
JAVASCRIPT style 中visibility和display之间的区别
javascript 拖放效果实现代码
jquery last-child 列表最后一项的样式
Jquery实战_读书笔记1—选择jQuery

Javascript 中的 Mozilla的JavaScript引擎__noSuchMethod__()方法


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-09-28   浏览: 66 ::
收藏到网摘: n/a

JavaScript中有很多内部属性和方法,在大多数情况下,只有JavaScript引擎才可以访问,但不论什么都是有特例的,在这里就是指Mozilla的JavaScript引擎,包括SpiderMonkey和Rhino,都提供了若干接口来访问这些内部属性,如果加以合理利用的话,不仅可以让JavaScript更加健壮,还可以开发出一些有意思的功能,比如本文介绍的__noSuchMethod__()方法就是其中之一。

著作权声明

本文译自 Nicholas C. Zakas 于2009年2月17日在个人网站上发表的《Mozilla JavaScript extension: __noSuchMethod__》。原文是唯一的正式版,本文是经过原作者(Nicholas C. Zakas)授权的简体中文翻译版(Simplified Chinese Translation)。译者(明达)在翻译的准确性上做了大量的努力,并承诺译文的内容完全忠于原文,但可能还是包含疏漏和不妥之处,欢迎大家指正。译注的内容是非正式的,仅代表译者个人观点。

以下是对原文的翻译:

和其它浏览器相比,Mozilla的JavaScript引擎总会有一些与众不同的亮点。SpiderMonkey和他的好搭档Rhino(用 Java实现的JavaScript引擎)都提供了很多扩展特性,可以帮助我们开发更加健壮的JavaScript应用。其中之一就是本地对象的__noSuchMethod__()方法。在大多数JavaScript引擎中,访问一个不存在的方法时都只会简单的抛出错误,而在Mozilla的引擎中,这只是默认行为,我们可以通过覆盖某个对象的__noSuchMethod__()方来来重新定义这个行为。当这个对象试图调用一个不存在的方法时,就会触发该对象的__noSuchMethod__()方法。

当__noSuchMethod__()方法被调用时,JavaScript引擎会传入两个参数,一个是调用方法的名称,一个是参数数组,对应于要传递给调用方法的所有参数,注意这个参数数组应该是一个Array对象,而不是arguments对象,而且就算没有参数,也要传递一个空数组,下面举一个简单的例子加以说明:

// 注意,下面的代码只有在使用SpiderMonkey或者Rhino的浏览器中才会被正确解析
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__()方法。当调用person对象的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("");
    },
    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()和text()这三个方法,而是为每一个有效的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__()发挥真正作用的时候。让我们来看看用__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”就可以,在__noSuchMethod__()中,会对方法名的首字母进行判断,如果首字母是“x”,就会标记为结束标签,并将“x”从方法名称中去掉。接下来,会通过Mozilla的数组扩展 indexOf()来判断方法名称是否在可用标签的数组里面,如果方法名是无效的,就会抛出一个错误;如果方法名是有效的,就会返回生成的标签字符串。代码所支持的标签数量是可以动态设置的,我们只需要对标签列表数组进行修改,就可以达到添加或者删除“方法”的目的。

很显然,由于这个特性不能跨浏览器,所以肯定不能用于通常的情况下。但对于那些专门针对Mozilla引擎(比如Firefox等)的JavaScript应用来说,这无疑为我们敞开了一道神奇的大门,尤其在开发动态接口时,__noSuchMethod__()将是一个非常强有力的工具。