Juan
Juan

Reputation: 5758

Why do I need to write "function(value) {return my_function(value);}" as a callback in node.js?

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

Answers (3)

Rafael
Rafael

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

Scott Sauyet
Scott Sauyet

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

Pointy
Pointy

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

Related Questions