Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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' ]
> 
like image 268
Juan Avatar asked Dec 14 '13 02:12

Juan


3 Answers

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.

like image 76
Pointy Avatar answered Oct 15 '22 15:10

Pointy


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));
like image 25
Scott Sauyet Avatar answered Oct 15 '22 16:10

Scott Sauyet


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));
like image 22
Rafael Avatar answered Oct 15 '22 14:10

Rafael