9

Please, can someone tell me what does this.init.apply(this, arguments) do in the code below?

I understand what apply() does in general, but in the context of the code below, what is it doing in there?

var Class = function() {

    var klass = function() {
        this.init.apply(this, arguments); //I don't really get this bit...
    };

    klass.prototype.init = function(){};

    return klass;
};

var Person = new Class;

//Usage
var someone =  new Person;

I see a lot of people using it. I've got an idea of what it does but can't really put my hands on it so I need more light.

I'm going up an extra level in JS, so I wanna know everything about it, not just the simple 'Hello world' level.

Many thanks

Shaoz
  • 10,573
  • 26
  • 72
  • 100
  • 5
    https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply – SLaks May 15 '12 at 19:48
  • 2
    possible duplicate of [Apply() question for javascript](http://stackoverflow.com/questions/4638450/apply-question-for-javascript) – kapa May 15 '12 at 19:49
  • 4
    Was there something unclear about how the method was described when you googled for it? – Jeff May 15 '12 at 19:50
  • 2
    Thanks @Jeff. Yes, I don't understand why `init` is defined twice in the code above. The question I asked was for the context in which `apply()` applied. – Shaoz May 15 '12 at 19:53

1 Answers1

9

apply is a member function of a function object. Suppose we have:

function saySomething(thing, anotherThing) {
    alert(this + " says " + thing + " and " + anotherThing);
}

Then we can use:

saySomething.apply(document, ["hello", "goodbye"]);

This calls the function and supplies the values of the array as arguments to the function. The first argument species the context of the function (or, what this equals when the function runs).

You should also be aware that arguments is a special variable that holds an array of all arguments passed to the function. So, here, this.init.apply(this, arguments) means that the init function is called and passed all the of arguments that were passed to the klass constructor.

In a real implementation, I think init would expect arguments. Consider how this would be done without apply:

var klass = function(arg1, arg2, arg3) {
    init(arg1, arg2, arg3);
}

klass.prototype.init = function(arg1, arg2, arg3) {}

If you wanted to add arg4 to init, you'd have add it in three places! By having klass transparently pass all its arguments to init, you make you code much less brittle.

apsillers
  • 112,806
  • 17
  • 235
  • 239
  • Many thanks @apsillers. But why is it calling `init()` inside itself? Why not just use `klass.prototype.init()`? Sorry for bugging you about this, I like to be clear on things... – Shaoz May 15 '12 at 20:17
  • 2
    It's designed to make `klass` completely transparent -- although `klass` is what gets called when building a new instance, `init` is the function does the real "heavy lifting" and it may expect arguments. To save you the trouble of duplicating an argument list on `klass` and `init`, `klass` takes no named arguments and simply passes all arguments to `init` by using `apply` and `arguments`. Why was it done this way? I don't know enought about the Klass library to say. – apsillers May 15 '12 at 20:25
  • Edited for further clarification. – apsillers May 15 '12 at 20:30
  • Now I get it, thank you very much. That's the explanation I wanted to clear things.... But instead of this technique, could an object been used as an argument? As in key/value properties as arguments... i.e. `{key1: value1, key2: value2,...keyN: valueN}`... – Shaoz May 15 '12 at 20:58
  • Sure, that's a perfectly valid and not uncommon pattern, and you could have use it instead of (or in conjunction with) the apply/arguments pattern. – apsillers May 15 '12 at 22:12