Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

javascript higher order functions ; "this" parameters vs external "self" variable [closed]

Tags:

javascript

When using higher order function of the Array API in javascript (forEach, map, filter, etc.) there are 2 means to pass "this" variable :

myArray.forEach(function(value) {
    this.aContextualFunction();
}, this);

Or

var self = this;
myArray.forEach(function(value) {
    self.aContextualFunction();
});

Which one is the better ? What are the pros and cons ?

Example: http://jsfiddle.net/TkZgX/

like image 617
Molochdaa Avatar asked Oct 22 '12 08:10

Molochdaa


2 Answers

I always prefer the first one.

pro: no extra var declaration

con: maybe confusion as seen in the comments on this question..

like image 127
lrsjng Avatar answered Nov 12 '22 10:11

lrsjng


When using higher order functions I prefer my functions not to make any assumptions about the callbacks it receives as arguments. In general, the more loosely coupled the code the better.

For example, say I write a higher order function for forEach:

function forEach(array, callback, that) { // that is optional
    var length = array.length;
    for (var i = 0; i < length; i++)
        callback.call(that, array[i], i); // pass the value and the index
}

Now say I want to use it:

Array.prototype.double = function () {
    forEach(this, function (value, index) {
        this[index] = 2 * value;
    });                                     // oops, I forgot that
};

var array = [1, 2, 3];
array.double();

The above code will cause variables to leak into the global scope. Not a good thing. See the demo here: http://jsfiddle.net/8dad4/

What's the alternative? Remove the optional third parameter and use closures:

function forEach(array, callback) {
    var length = array.length;
    for (var i = 0; i < length; i++)
        callback(array[i], i);
}

Not only is the code smaller, but there won't be any accidental global leaks (unless you use this instead of the external that like an idiot). Let's see an example:

Array.prototype.double = function () {
    var that = this;

    forEach(this, function (value, index) {
        that[index] = 2 * value;
    });
};

var array = [1, 2, 3];
array.double();

The demo is here: http://jsfiddle.net/8dad4/1/

Hmmm... that doesn't seem very enticing - I don't want to create a new variable. May we do something better? Yes, we sure can. This is the method I prefer (we still use the second forEach function):

Array.prototype.double = function () {
    forEach(this, function (value, index) {
        this[index] = 2 * value;
    }.bind(this));
};

var array = [1, 2, 3];
array.double();

The demo is here: http://jsfiddle.net/8dad4/2/

Wow, isn't this better? We combined both methods one and two. Advantages:

  1. The forEach function doesn't assume anything. The code is more loosely coupled.
  2. We don't need an external variable like that. No closures needed.
  3. There's no confusion as to what's happening.

We can do this because the anonymous function passed to forEach is a function expression. So we just append .bind(this) to it and we're done.

like image 26
Aadit M Shah Avatar answered Nov 12 '22 11:11

Aadit M Shah