2

Im trying to get method chaining to work using javascript:

(function(){
    var first = function(){
        console.log("1st Chain");
        return this;
    };

    var second = function(){
        console.log("2nd Chain");
    }

    first().second();
})();

Only the first function is printing to the console but the second function is saying its undefined. However when I tried it using a Constructor, it works.

var Chaining = function(){
   this.first = function(){
       console.log("1st Chain");
       return this;
   };

   this.second = function(){
       console.log("2nd Chain");
   };
};

var chain = new Chaining;
chain.first().second(); // this works fine.
5
  • 2
    Simply log this in the first function. Commented Jan 22, 2015 at 20:03
  • So what is the question? Commented Jan 22, 2015 at 20:04
  • 1
    Why not call first function in second function? Commented Jan 22, 2015 at 20:06
  • 1
    You don't quite yet get what this is about in javascript. Commented Jan 22, 2015 at 20:08
  • This is comparing apples with oranges Commented Jan 22, 2015 at 20:37

3 Answers 3

6

In the first Chain this is bound to the window and therefore second is not visible (undefined in that scope).

(function(){

    var first = function(){
        console.log("1st Chain");
        console.log(this);
        return this;
    };

    window.second = function(){
        console.log("2nd Chain");
    }

    first().second();
})();

To get rid of an export to the global window object of the second function, you could use a Object that's only visible in the Scope of the anonymous function.

(function(){

    var Chain = {};

    Chain.first = function(){
        console.log("1st Chain");
        console.log(this);
        return this;
    };

    Chain.second = function(){
        console.log("2nd Chain");
        return this;
    }

    // example
    Chain.first().second().first();

    // example export 
    // window.Chain = Chain;

})();

If you want to chain in another scope, you could export your Chain to the window and use it without new, ie. Chain.first().second();.

You could also save a pointer to this (as pointed out by Jonathon):

(function(){

    var self = this;

    this.first = function(){
        console.log("1st Chain");
        console.log(this);
        return self;
    };

    this.second = function(){
        console.log("2nd Chain");
        return self;
    }

    // example
    first().second().first();

    // export example
    // window.Chain = self;
})();

// exported anonymous function to Chain    
// Chain.first().second();

Saving a pointer to this is sometimes necessary, because the this keyword is scope-changing and refers to the context of the executed function. this does not refer to the instance of the object, where this is used, like you would expect in Java.

Every function can therefore bound to another scope. To adjust the function context use bind, apply and call.

Sign up to request clarification or add additional context in comments.

4 Comments

sorry Im a newbie to javascript, can i ask what is the second function bound to then if its not bound to the window.
ie. first is a function visible in the scope of an anonymous function, i think scope and this is an interesting read.
It's a terrible idea to expose a function into a global scope instead of returning some locally scoped object.
yeah, i updated the answer to show a slightly better aproach without cluttering the global scope.
1

When you use this in the context of the global object, you make global variables and obliterate them if they already exist. When in doubt, log this and if it's the global object...

Don't do this.

Here's an option that gets you the behavior you're looking for:

var chaining = function() { 
  return {
    first: function() { 
      console.log("first()");
      return this; 
    },
    second: function() { 
      console.log("second()"); 
    },
    all: function() { 
      this.first().second();
    }
  }
};

chaining().all();

var chain = chaining(); 
chain.first().second(); 

This outputs first(), second(), first(), second() as you probably would expect. That's because this is used in the context of the object returned by calling chaining().

More information and good reading about this

Comments

1
(
  function(){
    var that = this;

    this.first = function () {
      console.log("1st Chain");
      return that;
    };

    this.second = function () {
      console.log("2nd Chain");
      return that;
    }

    first().second();
  }()
);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.