JavaScript Has Built-In Mix-ins With ‘apply’ Or ‘call’

While I was running the Object-Oriented JavaScript discussion / demo at Pablo’s Fiesta this weekend, Jimmy Bogard asked me to try something fun. I had a small constructor function defined with a couple of methods defined directly in it.

function Stuff() {
  this.whatever = function(){
    $("#results").text("whatever was called");
  }

  // ... other stuff here
}

I also had an object literal with no methods defined, and was showing something (I don’t remember what, at the moment). Jimmy asked me to call ‘apply’ on the constructor function and pass my object literal into it.

foo = {};
Stuff.apply(foo);

Then he asked me to call one of the methods from the function constructor on my object literal instance.

foo.whatever(); // #=> "whatever was called"

I expected this to fail, because I didn’t think the method would be around on my object literal. I was wrong, of course! Here’s that code running in a live JSFiddle (click the ‘result’ tab if you’re seeing the embedded version in this post).

CRAZY! … or… simply exposing how constructor functions actually work, exposing an easy way to do mixins with JavaScript?

Here’s what’s happening:

1) When I call the function using `apply`, the first parameter i used as the context of the call. Therefore, `this` inside of the function refers to the object that I’ve passed in to `apply`. When `this.someMethod = function(){…}` is called, ‘this’ is the object i passed in.

2) I’m allowed to add any function I want to any object I want at any time, simply by assigning the function to an attribute on the object. Therefore, when `this.someMethod = …` is called, it’s as if I was directly calling `foo.someMethod = …` directly.

With this in mind it seems that JavaScript has mix-ins built right in. There’s no need to use something like underscore.js’ `extend` method. But I wonder: are there any gotchas to this scenario? Anything that I need to watch our for? I’m going to have to play a little more to see what the effects are, what scenarios really work well and don’t, etc.


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://domenicdenicola.com/ Domenic Denicola

    This will only work with per-instance constructor-attached methods (“privileged methods” in Crockford’s terminology); if you use the prototypal pattern, i.e. Stuff.prototype.whatever = function () { … }, those methods (Crockford’s “public methods”) will not be mixed in.

    • http://mutedsolutions.com Derick Bailey

      ah, that makes sense. if a method is added to the prototype via ‘Stuff.prototype.another = function(){…}’, then it’s not getting assigned to the context object when i call Stuff.apply.

  • guest

    You should take a look at how underscore built extend… it actually leverages apply (And there is another one as well, I dont recall it at the moment). So, I would say there is no downside of doing it yourself vs. using underscores version, since they are both essentially the same thing.

    • http://mutedsolutions.com Derick Bailey

      yeah, i use underscore’s extend pretty regularly. love it. :)

  • David A R Kemp

    one thing that’s often done in constructor functions is to alias “this” (i.e. the initial context):

    function Something() {
        var self = this; //store reference to context
        self.count = 0;
        self.doSomething = function() {
           self.count += 1;
       }
    }

    so, if you wanted, you could change your original code to

    function Something(self) {
        var self = self || this;
        self.whatever = function() {
          $(“#results”).append(“whatever was called. “);
        }

        return self;
    }

    this way, you can call Something like this:

    var foo = new Something(); //
    var bar {};
    Something.apply(bar);
    var baz = Something({});

    • http://mutedsolutions.com Derick Bailey

      now that’s an interesting idea! thanks, David :)

  • http://twitter.com/ozzymcduff Oskar Gewalli

    Extend works on two objects. call/apply works on “constructor” and “object”.

  • http://dev.bennage.com Christopher Bennage

    I’d also be cautious using this on objects you don’t ‘own’, since you could easily whack properties/functions that you might not want to,

  • Anonymous

    This reminds of mixing in modules to already created instances in ruby. It got me think about if you could extend Function.prototype in order to make applying the proxy pattern easier. 

    Good things can happen when you understand what .call and .apply do