-1

Dealing with the robots node library, I noticed that

var robots = new require('robots').RobotsParser();

differs from

var robots = new (require('robots')).RobotsParser();

The first require fails lamenting that a this.someFunction() doesn't exist, while the second succeeds. For some reason, the this object in the first line above apparently refers to the global object, while in the second line it's bound to the robots module. Why?

The error I receive is:

/home/user/crawler/lib/robots/lib/parser.js:44
    this.setUrl(url, after_parse);
         ^
TypeError: Object #<Object> has no method 'setUrl'

setUrl is the actual someFunction mentioned in the example.

davide
  • 2,082
  • 3
  • 21
  • 30
  • I'm voting to close this question as off-topic because OP didn't follow the [usage instructions](https://github.com/ekalinin/robots.js#usage) for the repo and is then surprised that it doesn't work. – Evan Davis May 14 '15 at 15:41
  • 1
    possible duplicate of [How does require work with new operator in node.js?](http://stackoverflow.com/questions/17604497/how-does-require-work-with-new-operator-in-node-js) – Leonid Beschastny May 14 '15 at 15:45
  • @Mathletics There is a wrong usage, but it's still demonstrating a particular case of unexpected behavior that can be answered. IMO calling it off-topic is overkill. – E_net4 May 14 '15 at 15:46
  • @E_net4 that's the beauty of the voting system: I am but one vote. In any case, an actual dupe was found. – Evan Davis May 14 '15 at 15:48
  • @davide there is no relationship between `require` and `this`; `require` is merely a function like any other in JS. – Evan Davis May 14 '15 at 15:50

2 Answers2

1
var robots = new require('robots').RobotsParser();

is parsed as

var robots = (new require('robots')).RobotsParser();

i.e. it tries to call the RobotsParser method of a require() instance. Not what you wanted!

Scimonster
  • 32,893
  • 9
  • 77
  • 89
1

The first line makes a constructor invocation of require, which effectively modifies the this reference at the scope of the library to point to a new, supposed instance of require. This is incorrect, and require should always be called as a regular function. Adding the parenthesis (as in the second line) clears the issue, as it will instead create a new instance of RobotsParser.

E_net4
  • 27,810
  • 13
  • 101
  • 139
  • Thank you @E_net4. I'm confused because the member access operator (`.`) has higher priority than `new`, but this doesn't seem to be a problem about operator priority. Can you point me to some docs which shade light on this? – davide May 14 '15 at 16:05
  • 2
    Your problem _does seem_ to be about operator priority. Writing `new foo().a()` will call the member function `a` of a new instance of `foo`. If you are wondering how `this` works, a small search will lead you to some good sources. Have a look at [this one](http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/). – E_net4 May 14 '15 at 16:08
  • Thank you, I've read the linked article on "JS Is Sexy". Still, I don't get why in `new foo().a()` the function `a` is called on the new instance of `foo` instead of the old one. If `new` has a lower priority than `.`, why is the member function `a` executed after `new`? MDN docs seem shallow on this specific detail. – davide May 14 '15 at 17:57
  • It does _not_ have lower priority. The behavior is well defined and the opposite of what you are thinking. Besides, there's no old instance either, just a new one unintentionally created. – E_net4 May 14 '15 at 18:00