Freewind
Freewind

Reputation: 198338

How to invoke outer "this" in inner function?

I defined two functions for array:

Array.prototype.remove = function(obj) {
    var i = this.length;
    while (i--) {
        if (this[i] === obj) {
            this.removeAt(i);
        }
    }
};
Array.prototype.removeAll = function(array2) {
    array2.forEach(function(item) {
        this.remove(item);  // remove not found!!
    });
}

But in the removeAll function, it reports function remove is not found. I fix it like this:

Array.prototype.removeAll = function(array2) {
    var outer = this;
    array2.forEach(function(item) {
        outer.remove(item);  
    });
}

But it's ugly. Is there a better way?

Upvotes: 5

Views: 1391

Answers (4)

abuduba
abuduba

Reputation: 5042

By passing next one argument to forEach which will be context of this in callback function, In your case this refers to window object.

Array.prototype.removeAll = function(array2) {

    array2.forEach(function(item) {
        this.remove(item);  
    },this);
}

Upvotes: 2

Martin Jespersen
Martin Jespersen

Reputation: 26183

An alternative to using bind (if you need to support old browsers and don't wish to extend Function.prototype) is to simply wrap your callback in an immidate function and feed this in as an argument like this:

Array.prototype.removeAll = function(array2) {
    array2.forEach(function(outer){
     return function(item) {
        outer.remove(item);  
    };}(this));
}

or you can write a simple curry utility function and use like this

function curry() {
  var fn = Array.prototype.shift.call(arguments), 
      args = Array.prototype.slice.call(arguments);
  return function curryed() {
    return fn.apply(this, args.concat(Array.prototype.slice.call(arguments)));
  };
};



Array.prototype.removeAll = function(array2) {
    array2.forEach(curry(function(item) {
        outer.remove(item);  
    },this));
}

If you don't mind extending Function.prototype you can use bind as already described by others you can find an excellent compatibility extension on MDN here: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind

Upvotes: 2

user166390
user166390

Reputation:

There is Function.bind and similar.

array2.forEach((function(item) {
    this.remove(item);  
}).bind(this));

It's not technically the same, as the previous the "inner this" is now shadowed/lost (and a new wrapper function is created), but it works nicely in some contexts.

For the most part, I prefer the standard var self = this ...

Happy coding.

Upvotes: 1

Quentin
Quentin

Reputation: 944203

Passing this via a different variable as you do is the idiomatic approach. There is nothing ugly about it. (It is more common to call the variable that or self though)

Upvotes: 6

Related Questions