簡體   English   中英

Javascript:對象返回自己a.k.a. chaining

[英]Javascript: object return itself a.k.a. chaining

我正在嘗試構建自己的小jquery類庫,但是我正在創建這個鏈接模式的時間非常艱難。 基本上我有一個類有一堆方法,可以更容易地操作文檔。 這是一個例子

function MF(selector){
    var DO; // Stands for DocumentObject
    this.select = function(selector){
        return document.getElementById(selector);
    }
    if(typeof selector === 'string'){
        DO = this.select(selector);
    }else if(selector instanceof HTMLElement){
        DO = selector;
    }

    this.children = function children(selector){
        return DO.getElementsByClassName(selector);
    }
    return {
        MF: ???
    }
}(null);

我的反思可能有問題,但我想弄清楚的是,為了獲得文檔對象(html元素)的其他方法,我需要擴展HTMLElement原型或者將元素與我的類一起傳遞。 我選擇了第二種選擇。 我只是無法弄清楚我的班級要回歸什么,以便我可以繼續進行鏈接。 為了這個例子,我簡單的目標是能夠編寫以下代碼行:

MF('someDiv').children('someClass');

在絕望的嘗試中,我嘗試返回一個新的MF實例,默認情況下不應該有實例,並導致自己進入無限循環。 我真的無法想象我應該回到那里。 任何幫助是極大的贊賞!

return this; 將允許訪問構造函數的方法。 如果該方法不需要返回另一個值,請在構造函數的最底部以及屬於它的每個方法的最底部執行此操作。

function MF(selector){
  var doc = document;
  this.select = function(selector){
    return doc.getElementById(selector);
  }
  // there are problems with some of your code
  this.someMethod = function(){
    /* do stuff - If you want to access an Element then
      var thisIsNowGlobal = this.select('someId');
      thisIsNowGlobal.innerHTML = 'someText';
      Note, the keyword this is global not var
      If you wrote this.select('someId').innerHTML the property would not exist

      When a property of an Object is assigned to a variable or argument
      the this value changes to the global context.
   */
    return this;
  }
  return this;
}

看起來你也試圖使用模塊模式,並沒有利用原型..

當你想鏈接某些東西時,你需要在可鏈接的方法中返回它自己( this ),或者返回你的Objectnew實例。 在下面的例子中,我通過使用新實例來實現鏈接(好像孩子們看起來需要成為一個列表,所以我做了一個數組 )。

var MF = (function () { // module pattern start
    function MF(selector) {
        if (!(this instanceof MF)) return new MF(selector); // always construct
        this.node = null; // expose your DO
        if (typeof selector === 'string') {
            this.node = document.getElementById(selector);
        } else if (selector instanceof HTMLElement) {
            this.node = selector;
        } else {
            throw new TypeError('Illegal invocation');
        }
    }
    MF.prototype = {}; // set up any inheritance
    MF.prototype.select = function (selector) {
        return new MF(document.getElementById(selector)); // returns new instance
    };
    MF.prototype.children = function (selector) {
        var MFs = [],
            nodes = this.node.getElementsByClassName(selector),
            i;
        for (i = 0; i < nodes.length; ++i) {
            MFs[i] = new MF(nodes[i]);
        }
        return MFs; // array of items of new instances
    };
    return MF; // pass refence out
}()); // module pattern end

然后,例如,您可以鏈接...

MF(document.body).children('answer')[0].children('post-text')[0].node;

你可以很容易地做到這一點。 請記住,當你return this它時,如果this有定義的方法,那么你可以按順序調用它們。

var MyUtilThing = function(){};
MyUtilThing.prototype.doStuff = function doStuff (){ // give it a name, helps in debugging
  // do your thing
  console.log('doing stuff');
  return this; // this is your instance of MyUtilThing
}

var thing = new MyUtilThing();
thing.doStuff().doStuff().doStuff(); // etc

必須明確創建實例的一種方法是在構造函數中執行此操作。

var MyUtilThing = function(selector){
  var F = function(){};
  F.prototype = MyUtilThing.prototype;
  var toReturn = new F();
  toReturn.initialize(selector);
  return toReturn;
};

MyUtilThing.prototype.initialize = function initialize(selector){
  this.selector = selector;
};

MyUtilThing.prototype.doStuff = function doStuff (){ // give it a name, helps in debugging
  // do your thing
  console.log('doing stuff to', this.selector);
  return this; // this is your instance created in the constructor (the blank function with the same prototype as MyUtilThing)
}

var thing = MyUtilThing('div'); // no use of new here!
thing.doStuff().doStuff().doStuff(); // etc

但是,在那里進入一些稍微沉重的領土。 最好的辦法就是嘗試和了解究竟如何this是JS使用,你會得到一個很長的路要走。

傳統上,jQuery啟用鏈接的方式是為每種類型的返回值創建一個包裝器對象。 例如,在您的情況下,為HTMLElement創建自己的包裝器是HTMLElement

function HTMLElementWrapper(element) {
    if (element instanceof HTMLElementWrapper) return element;
    this.element = element;
}

現在您有了一個HTMLElementWrapper您可以按如下方式重構您的MF功能:

function MF(selector) {
    return new HTMLElementWrapper(typeof selector === "string" ?
        document.getElementById(selector) : selector);
}

MF函數現在返回一個HTMLElementWrapper對象,它有兩個方法selectchildren

HTMLElementWrapper.prototype.select = function (selector) {
    return new HTMLElementWrapper(this.element.getElementById(selector));
};

HTMLElementWrapper.prototype.children = function (selector) {
    return new NodeListWrapper(this.element.getElementsByClassName(selector));
};

Ofcourse為children功能工作,你需要創建一個NodeListWrapper構造函數:

function NodeListWrapper(list) {
    if (list instanceof NodeListWrapper) return list;
    this.list = list;
}

現在您可以按如下方式鏈接方法:

MF("someDiv").select("something").children("someClass");

要在.children("someClass")之后鏈接方法,您需要將這些方法添加到NodeListWrapper.prototype

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM