1

I am switching from Java to NodeJs so some things are still blurry to me.

I am trying to work with scripts as I would do with classes in Java. I've learned this is the way to do it:

var client = require('scp2');
var host, username, password;

var SftpHandler = function (host, username, password) {
  this.host = host;
  this.username = username;
  this.password = password;
 };



SftpHandler.prototype.downloadFile = function (path, callback) {
    console.log(this.host,username,password,path);
};

module.exports = SftpHandler;

The problem is when I call it from another script like this:

var sftpHandler = new SftpHandler(credentials.sftpHost, credentials.sftpUsername, credentials.sftpPassword);
sftpHandler.downloadFile(credentials.sftpPathToImportFiles+configFile.importFileName, callback);

I am having 162.*.*.* undefined undefined undefined ... in the console log.

I've realized it is due to I am lacking this. in the object attributes I am referring to. But why is this. needed? Is that the right way to do it?

Levi Roberts
  • 1,277
  • 3
  • 22
  • 44
Ondrej Tokar
  • 4,898
  • 8
  • 53
  • 103

2 Answers2

2

It's a little tricky to map concepts between Java and JavaScript sometimes.

The short answer is, yes, if you are going to try and make something that's like a class instance in Java in JavaScript, then you need to call 'this' every time.

The reason is that this in JS is actually a special, locally scoped variable inside a function that refers to the calling scope. It's not always the actual class instance, believe it or not, so you need to read up on it more thoroughly.

Many folks choose not to try, as there are a number of places that following Java idioms will either get you into trouble, or else just make things more difficult / complex / hard to maintain.

But in any case, as an example of how this can change, if your downloadFile method needed to provide a nested function, for example you wanted to handle a callback with an anonymous function:

SftpHandler.prototype.downloadFile = function (path, callback) {
    console.log(this.host); // this here refers to your object instance
    fileManager.getFile(path, function(e, file){
       console.log(this.host); // 'this' here refers to the anonymous function, not your object
    })
};

Hope that helps.

** Edit for how to get to this inside the callback **

There's a couple ways to maintain the reference. It's very common to just set another variable in scope to the original this, like so:

SftpHandler.prototype.downloadFile = function (path, callback) {
    console.log(this.host); // this here refers to your object instance
    var self = this;

    fileManager.getFile(path, function(e, file){
       console.log(this.host); // 'this' here refers to the anonymous function, not your object
       console.log(self.host); // 'self' there refers to the enclosing method's 'this'
    })
};

Others prefer to be more explicit with the use of Function#bind:

SftpHandler.prototype.downloadFile = function (path, callback) {
    console.log(this.host); // this here refers to your object instance
    fileManager.getFile(path, function(e, file){
       console.log(this.host); // 'this' here refers to the your object thanks to bind()
    }.bind(this));
};
Paul
  • 35,689
  • 11
  • 93
  • 122
  • I see @Paul thank you. As in your example is written, `this` in the nested function refers to its own parameter. So how would you normally access the instance/object attribute from within that function? +1 btw – Ondrej Tokar Jul 29 '16 at 09:56
  • That's what I though. But I thought it's a dirty solution. Thanks for a reference. – Ondrej Tokar Jul 29 '16 at 10:02
1

To avoid using the this your module can be a function that returns an object:

var client = require('scp2');

var SftpHandler = function (host, username, password) {

  return {
    downloadFile: downloadFile
  };

  function downloadFile (path, callback) {
    console.log(host, username, password,path);
  }
};

module.exports = SftpHandler;

And then you call this function without the new:

var sftpHandler = SftpHandler(credentials.sftpHost, credentials.sftpUsername, credentials.sftpPassword);
sftpHandler.downloadFile(credentials.sftpPathToImportFiles+configFile.importFileName, callback);
Fabio Antunes
  • 22,251
  • 15
  • 81
  • 96