Reputation: 5758
totally new to JS so please forgive if this is mind-bogglingly obvious.
Suppose I want to filter a list of strings with a function f that maps string -> bool. This works:
filteredList = list.filter(function(x) { return f(x); })
This fails:
filteredList = list.filter(f)
Why???
Code example:
~/projects/node (master)$ node
> var items = ["node.js", "file.txt"]
undefined
> var regex = new RegExp('\\.js$')
undefined
> items.filter(regex.test)
TypeError: Method RegExp.prototype.test called on incompatible receiver undefined
at test (native)
at Array.filter (native)
at repl:1:8
at REPLServer.self.eval (repl.js:110:21)
at Interface.<anonymous> (repl.js:239:12)
at Interface.EventEmitter.emit (events.js:95:17)
at Interface._onLine (readline.js:202:10)
at Interface._line (readline.js:531:8)
at Interface._ttyWrite (readline.js:760:14)
at ReadStream.onkeypress (readline.js:99:10)
> items.filter(function(value) { return regex.test(value); } )
[ 'node.js' ]
>
Upvotes: 16
Views: 3444
Reputation: 7746
As others have said, this
is undefined
when the function reference is called. I'd like to offer a non-reflexive, slightly verbose alternative:
items.filter(RegExp.prototype.test.bind(/regex/g));
Upvotes: 6
Reputation: 50797
The reason you often can't do this is that functions used as methods are not simply methods. If you use them without invoking them as methods they are then divorced of their original context. You can get around this with Function.prototype.bind
:
items.filter(regex.test.bind(regex));
Upvotes: 8
Reputation: 413737
You're passing a reference to the "test" function, but when it gets called the regular expression object won't be around. In other words, inside "test" the value of this
will be undefined
.
You can avoid that:
items.filter(regex.test.bind(regex))
The .bind()
method will return a function that'll always run with the value of "regex" as this
.
Upvotes: 28