无法在同一个类JS的另一个方法中调用方法

时间:2017-11-23 13:04:24

标签: javascript node.js oop ssh2-sftp

我试图在同一个类的方法连接中调用方法测试。但我得到的只是" Uncaught Type Error:无法读取属性' test'未定义"。 如何访问sftp回调中的任何变量? 为什么会这样?

这是我的代码:



const SSH2 = require('ssh2').Client;
class SshClient {
  constructor(host, username, password) {
    this.host = host;
    this.username = username;
    this.password = password;
    this.port = 22;
    this.client = null;
  }

  test(testvar) {
    console.log(testvar);
  }

  connect() {
    this.client = new SSH2();
    let client = this.client;
    let username = this.username;
    this.client.connect({
      host: this.host,
      port: this.port,
      username: this.username,
      password: this.password
    });
    this.client.on('ready', function() {
      console.log('Client :: ready', client);
      client.sftp(function(err, sftp) {
        if (err) throw err;
        sftp.readdir('/home/' + username, function(err, list) {
          if (err) throw err;
          console.dir(list);
          this.test('hey');
          client.end();
        });
      });
    });
  }
}

let ssh = new SshClient('host', 'username', 'password');
ssh.connect();




2 个答案:

答案 0 :(得分:2)

使用function() {时,您将进入一个不属于您的类上下文的新上下文。使用es6 arrow functions,您可以轻松地将您的类上下文共享到内部函数中。

  this.client.on('ready', () => {
      client.sftp((err, sftp) => {
        if (err) throw err;

        sftp.readdir('/home/' + username, (err, list) => {
          if (err) throw err;

          this.test('hey');

          client.end();
        });
      });
    });

Here是关于es6 arrow functions如何运作以及它们如何影响this的好文章。

答案 1 :(得分:0)

当您将该函数用作回调(将其作为参数传递给另一个函数)时,回调中的this变量不会指向您的对象。

如果单独定义回调,它会更清晰:

class SshClient {
  constructor(host, username, password) {
    //...
  }

  test(testvar) {
    console.log(testvar);
  }

  connect() {
    this.client = new SSH2();
    // ...
    this.client.on('ready', onReadyCallback);
  }
}

function onReadyCallback() {
  console.log('Client :: ready', client);
  client.sftp(sftpCallback);
}

function sftpCallback(err, sftp) {
  if (err) throw err;
  sftp.readdir('/home/' + username, readdirCallback);
}

function readdirCallback(err, list) {
  if (err) throw err;
  console.dir(list);
  this.test('hey'); // It is clear that `this` here doesn't refer
                    // to the SshClient object
  client.end();
});

正如您所看到的,this中的readdirCallback看起来不再正常,该功能不属于SshClient类,而this可以不要指向SshClient对象。

最简单的解决方案是对代码中的clientusername变量执行相同的操作 - 将this保存到其他变量中:

  connect() {
    this.client = new SSH2();
    let self = this;
    // ...
    this.client.on('ready', function() {
       // we can use "self" variable here, 
       // as it's avaialbe from the outer scope
       self.client; // we can refer to client and username
       self.username;
       self.test(); // and we can call object methods
    });
  }

另一个替代方法是将回调分开并将对象捕获到另外的闭包中:

class SshClient {

  connect() {
    this.client = new SSH2();
    // ...
    this.client.on('ready', getOnReadyCallback(this));
  }
}

function getOnReadyCallback(sshClient) {
  function onReadyCallback() {
    console.log('Client :: ready', sshClient.client);
    sshClient.client.sftp(getSftpCallback(sshClient));
  }
}

另一个答案中提到的arrow functions可能是最好的解决方案,因为您不需要任何变通方法,但您必须清楚地了解问题是什么以及为什么箭头功能会解决它:

  

箭头函数表达式的语法短于函数表达式,并且没有自己的this,arguments,super或new.target。这些函数表达式最适合非方法函数,不能用作构造函数。

箭头功能没有自己的this - 因此,如果您使用箭头功能作为回调,原始对象的this仍可用。