0

I'm trying to call a method from a required Node module with a specific this object. As far as I see, there are three ways to do this, with .bind(obj)(args), or with .call(obj, arg1, ...), or with .apply(obj, aryArgs). I'm currently using bind, but I have tried all three with identical levels of not-success.

This is where I'm running the call:

var library = require("./library.js");

// ...

requestHandler.bind(library)(req);

requestHandler is a reference to the exported status function from this file:

exports.status = () => {
  console.log(this);
  this.render({text: "status ok"});
};

exports.paramSwitching = () => {
  this.render("rendered via param switching");
};

exports.json = () => {
  this.render({json: {this: 'renders', as: 'json'}});
};

exports.view = () => {
  this.render({view: true, locals: {text: 'hi'}});
};

I'd like this to work so that the status function is called with library as its this object, since that's where render is defined. However, the console.log statement is showing this as the evaluated contents of the file holding status, i.e.

{ status: [Function],
  paramSwitching: [Function],
  json: [Function],
  view: [Function] }

What's happening here, and how do I fix it? (Or, if I can't because Node is doing something weird, is there a workaround?)

ArtOfCode
  • 5,702
  • 5
  • 37
  • 56
  • Please include the code that defines `requestHandler`, given that it is not a reference to `.status` method in exports but rather the whole `exports` object – Pineda Mar 24 '17 at 12:15
  • @Pineda: It's already included. Read the question carefully – slebetman Mar 24 '17 at 12:16
  • As usual, whenever there is a misunderstanding of `this` I'll point readers to my answer to this question: http://stackoverflow.com/questions/13441307/how-does-the-this-keyword-in-javascript-act-within-an-object-literal/13441628?s=1|4.1585#13441628 – slebetman Mar 24 '17 at 12:17
  • @slebetman: Errr, it defines the binding of the object to library, but it could have been incorrectly referenced... It matters little given the fact that there are suitable answers now. – Pineda Mar 24 '17 at 12:20
  • @Pineda I did check the reference, and it's what it's meant to be - referencing `status`, not the whole module. – ArtOfCode Mar 24 '17 at 12:21

3 Answers3

1

The arrow function itself already binds the this within the function body function to the this of the context it was defined in. So you cannot change the this with any of those methods.

If you need to change the this then you cannot use arrow functions.

t.niese
  • 39,256
  • 9
  • 74
  • 101
1

Your request handler is declared with arrow notation:

exports.status = () => {
  console.log(this);
  this.render({text: "status ok"});
};

By design the arrow notation captures this at the time the function is declared. It is almost as if you did this:

exports.status = (function(){
  console.log(this);
  this.render({text: "status ok"});
}).bind(this);

This means the status() function is already bound and cannot be rebound. The solution is to stop using arrow functions:

exports.status = function(){
  console.log(this);
  this.render({text: "status ok"});
};
slebetman
  • 109,858
  • 19
  • 140
  • 171
1

Figured it out right after I posted this question. I've used arrow functions in the file containing status, which do not create their own this scope but use the enclosing context.

Calling bind, call or apply on these functions has no effect because this is already set to the function's enclosing context, which in this case is the eval'd file.

Switching the arrow functions out for regular functions (changing () => to function ()) has fixed the issue.

ArtOfCode
  • 5,702
  • 5
  • 37
  • 56