JavaScript >> Javascript 文檔 >  >> JavaScript

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 接口的強大盟友。

翻譯

  • 簡體中文

Tutorial JavaScript 教程
  1. Jelly Fin:貢獻者更新 9-12-2018

  2. 如何使用 Type Guards 在 TypeScript 中做任何事情

  3. 下面是我如何製作一個簡單的 Chrome 擴展來關閉所有打開的標籤

  4. Just Code 2020 - 前端 Web 開發者路線圖 - 公告

  5. 使用 CSS 和 Canvas API 重新創建 Instagram 過濾器功能

  6. 在 ReactJS 中使用 Bootstrap:reactstrap 還是 react-bootstrap?

  7. React 中的 Flux 架構入門

  1. 如何使用 Semantic UI React 在 DevExtreme Datagrid 中創建自定義編輯表單。

  2. Notion API 入門

  3. 根據彼此選擇的選項從 4 個選擇下拉列表中刪除選項? (允許使用 jQuery)

  4. 使用 Express 和 Cheerio 構建 Web-Scraped API

  5. 苗條的反應性和商店

  6. 使用代碼生成器搭建 Redux 樣板

  7. 在 TypeScript 中聲明全局變量

  1. JavaScript 數組交集 |簡單示例代碼

  2. 教 javascript 語言的 Javascript 書,而不是 dom

  3. 使用 Ethereal 進行電子郵件測試

  4. 移動網絡快速提示:電話號碼鏈接