1

I have the following javascript method:

String.prototype.includesAny = function(search) {
  var found = false;
  search.forEach(function(str) {
    if(this.toLowerCase().includes(str.toLowerCase())) {
      found = true;
    }
  });
  return found;
};

But it throws the error:

this.toLowerCase is not a function

I am thinking this is because this is not actually an instance of String at this point? Anybody knows the right way to do what I'm doing (and still use the prototype paradigm)?

wscourge
  • 10,657
  • 14
  • 59
  • 80
MoDiggity
  • 261
  • 2
  • 10
  • You have not bound the callback function to `this`. use the [`thisArg` argument of `forEach`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach). – trincot Nov 02 '16 at 19:13
  • Basically a duplicate of [How to access the correct `this` / context inside a callback?](http://stackoverflow.com/q/20279484/218196) – Felix Kling Nov 02 '16 at 19:23
  • Just a side note: this is not the very effective implementation. You will keep scanning an array after you have found first matching string, which is meaningless. You can just return `true` whenever you have found the first match. – Yeldar Kurmangaliyev Feb 02 '19 at 10:48

3 Answers3

1

In javascript this is function scoped, so creating a new function creates a new this.

Your forEach call has a callback, which is a function, and within that function this is no longer the string, but most likely the window

The solution is to simply store a reference to whatever this is in the outer function

String.prototype.includesAny = function(search) {
    var found = false,
        input = this;
    search.forEach(function(str) {
        if (input.toLowerCase().includes(str.toLowerCase())) {
            found = true;
        }
    });
    return found;
};

Array.forEach also has an optional thisArg that can be used

String.prototype.includesAny = function(search) {
    var found = false;

    search.forEach(function(str) {
        if (this.toLowerCase().includes(str.toLowerCase())) {
            found = true;
        }
    }, this);
    return found;
};

Or even better, use Array.some

String.prototype.includesAny = function(search) {
    return search.some(function(str) {
        return this.toLowerCase().includes(str.toLowerCase());
    }, this);
};

As a sidenote, extending native prototypes is generally a bad idea.

adeneo
  • 312,895
  • 29
  • 395
  • 388
0

You're probably correct about this not being a string because you are in the foreach. So store an instance of this in a variable before entering the foreach and use that instead.

var stringToCheck = this;
search.forEach(function...
TheValyreanGroup
  • 3,554
  • 2
  • 12
  • 30
0

You need to save your this in other variable to use it in other functions scope.

wscourge
  • 10,657
  • 14
  • 59
  • 80