Mozilla JavaScript extension: __noSuchMethod__
http://www.nczonline.net/blog/2009/02/17/mozilla-javascript-extension-nosuchmethod/
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__()将是一个非常强有力的工具。
相关推荐
在JavaScript的世界里,`__noSuchMethod__`是Mozilla Firefox浏览器特有的一种机制,它允许开发者处理对象上未定义的方法调用。这个特性在其他浏览器中并不通用,因此它的使用范围受到了一定的限制。`__noSuchMethod...
总的来说,Mozilla的SpiderMonkey提供了一种在C++应用程序中运行JavaScript代码的方法,这对于构建富客户端应用或者与Web服务交互非常有用。通过理解和利用SpiderMonkey的API,开发者可以将JavaScript的强大功能无缝...
在Java开发中,JavaScript引擎的使用日益广泛,其中Mozilla的Rhino引擎是备受开发者青睐的一款。本文将围绕"org.mozilla.javascript-1.7.2.jar"这个资源包,详细讲解其功能、原理以及在实际开发中的应用。 首先,...
《深入解析Mozilla JavaScript引擎:org.mozilla.javascript-1.7.2.jar.zip详解》 JavaScript,作为互联网上最广泛使用的脚本语言,其在Web开发中的地位不可动摇。而Mozilla的JavaScript实现,以其强大的功能和良好...
mozilla_nntp_heap_overflow
mozilla_certif_handle_dos
mozilla_default_perms
mozilla_multiple_flaws
mozilla_soapparameter_overflow
Mozilla Firefox,通称Firefox,中文也通称火狐,是一个自由及开源的网页浏览器[14],由Mozilla基金会及其子公司Mozilla公司开发。Firefox支持Windows、macOS及Linux,其移动版支持Android及Firefox OS,这些版本的...
本资源"mozilla_location_python-0.5.0-py3-none-any.whl"就是PyPI上发布的一个Python库,专为处理与Mozilla地理位置服务相关的任务而设计。 Mozilla地理位置服务是一个开放源代码项目,它允许设备通过Wi-Fi信号或...
Mozilla Firefox_18.0.2.rar 超好用的火狐版本,几年来,从搜狗、360,再到谷歌火狐,各种浏览器的不少版本都用过了,最终还是喜欢这个版本。 而且性能表现不错!20个页面才占用630M内存,15%CPU,而且一点卡顿的...
mozilla_firefox_cache_file
mozilla_firefox_xul_spoof
mozilla_firefox_code_exec
mozilla_firefox_files_rm
通过收集和分析Mozilla缺陷管理系统Bugzilla中的历史活动信息,可以介绍Mozilla缺陷报告仓库的概况。研究发现在Mozilla主要产品的新版本发布后,新的缺陷报告会有所激增。此外,严重等级较高的缺陷报告往往能在相对...
本书还包括详细的参考手册,涵盖了JavaScript的核心 API、遗留的客户端API和W3C标准DOM API,记述了这些API中的每一个JavaScript对象、方法、性质、构造函数、常量和事件处理程序。 这本最畅销的JavaScript参考书...