网络编程
位置:首页>> 网络编程>> JavaScript>> Mozilla专有JavaScript扩展之一(__noSuchMethod__)

Mozilla专有JavaScript扩展之一(__noSuchMethod__)

作者:明达 来源:七月佑安 发布时间:2009-03-01 12:45:00 

标签:Mozilla,扩展,JavaScript,属性,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__()将是一个非常强有力的工具。

0
投稿

猜你喜欢

  • 你是否曾为表单设计感到过沮丧或不知所措呢?接下来三篇文章,希望能彻底改变你的看法,真正爱上Web表单设计。首先感谢Luke Wroblews
  • 在我们建立一个数据库时,并且想将分散在各处的不同类型的数据库分类汇总在这个新建的数据库中时,尤其是在进行数据检验、净化和转换时,将会面临很大
  • 当我想要完美的使用:nth-child或者:nth-of-type的时候有点儿头晕。你越理解它们,就能写出越好的CSS规则!在这些简单的”秘
  • 包括安装时提示有挂起的操作、收缩数据库、压缩数据库、转移数据库给新用户以已存在用户权限、检查备份集、修复数据库等。 (一)挂起操作在安装S
  • ASP错误大全 Microsoft VBScript语法错误(0x800A03E9)-->内存不足 Microsoft VBScript语法
  • 我认为多选列表具有完美的功能——只需按下Ctrl键,同时点击鼠标从列表中选择多个项目。以下是一个典型的多选列表框: 上面那个列表框
  • 今天不小心又点了收藏夹里Google的新首页风格的地址,赫然发现又变了!从这个页面上线以来,偶尔会去看看,短短一年的时间,已经变换了至少三次
  • 一直很想做这个效果,原理是监听鼠标滚轮事件;可将此效果继续发散到其他应用上,如图片缩放,页面缩放等。演示:<!DOCTYPE html
  • 1、使用索引来更快地遍历表。缺省情况下建立的索引是非群集索引,但有时它并不是最佳的。在非群集索引下,数据在物理上随机存放在数据页上。合理的索
  • 维护是什么,维护就是修改,不断的修改,但是要保证你的html和css有清晰的版本界定,有扩展性,不要因为做的太死而重新去做这个页面。一个赚钱
  • 一、问题描述 SQL Plus WorkSheet是一个窗口图形界面的SQL语句编辑器,对于那些喜欢窗口界面而不喜欢字符界面的用户,该工具相
  • 使用MySQL,安全问题不能不注意。以下是MySQL提示的23个注意事项:1.如果客户端和服务器端的连接需要跨越并通过不可信任的网络,那么就
  • 本文给出了几个表单常用的js验证函数,有检查、\等特殊字符的,有检查是否含有空格,检查是否为Email 地址,也有检查是否是小数或负数的,检
  • DW2004的中文乱码情况你遇到过么?乱码一般是怎么出现的呢?也许很多时候用其他软件(比如Editplus)写程序的时候,忘了meta标签里
  • 本文主要介绍了一个获取SQL Server数据字典的经典SQL语句,大家可以根据各自的实际情况对这段语句进行相应的修改。SELECT sys
  • ASP从发布至今已经7年了,使用ASP技术已经相当成熟,自从微软推出了ASP.NET之后就逐渐停止了对ASP版本的更新。但是由于有很多人仍然
  • 下面继续为大家带来XHTML与HTML兼容的16条指引!1.避免将页面声明为XML类型,页面使用UTF-8或者UTF-16字符集。2.在空元
  • 注意:安装时要保证Oracle安装目录不能带有中文字符(如果第一次安装出现“加载数据库错误areasQueries”的错误,一般是因为Ora
  • 一:文字加粗 倾斜的代码文字加粗的代码是: <b>你好</b>文字倾斜的代码是: <i>你好!</
  • 写了一个小巧的jquery拾色工具,代码简单得不得了,只有这么几行:(function($){ $.fn.pickColor=fu
手机版 网络编程 asp之家 www.aspxhome.com