Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript: object return itself a.k.a. chaining

Tags:

javascript

I am trying to build my own little jquery-like library but I'm having a really rough time with creating this chaining pattern. Basically I have one class with a bunch of methods that make it easier to manipulate the document. Here's an example

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);

I might be wrong in my reflections but what I've come to figure out is that in order to have additional methods for a document object ( html element ) I either need to extend the HTMLElement prototype or pass the element along with my class. I've chosen the second option. I just can't figure out what to return in my class so that I can have chaining going on. What I simply aim at, for the sake of this example, is to be able to write the following line of code:

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

In a desperate attempt I tried returning a new instance of MF which should not have instances by default and led myself to an infinite loop. I really cannot figure what I'm supposed to return there. Any help is greatly appreciated!

like image 815
php_nub_qq Avatar asked Apr 09 '26 07:04

php_nub_qq


2 Answers

It looks like you also tried to use the module pattern, and haven't taken advantage of prototypes..

When you want to chain something, you either need to return itself (this) within the chainable methods, or return a new instance of your Object. In the example below I achieve chaining by using new instances (well the children looked like it needed to be a list so I did an Array of them).

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

Then, for example, you can chain like..

MF(document.body).children('answer')[0].children('post-text')[0].node;
like image 137
Paul S. Avatar answered Apr 11 '26 20:04

Paul S.


return this; will allow access to methods of the Constructor. Do it at the very bottom of the Constructor and the very bottom inside every method that belongs to it, if the method doesn't need to return another value.

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;
}
like image 41
StackSlave Avatar answered Apr 11 '26 19:04

StackSlave