【问题标题】:Not able to call method within another method of the same class JS无法在同一类 JS 的另一个方法中调用方法
【发布时间】:2018-05-07 11:06:46
【问题描述】:

我试图在同一个类的方法连接中调用方法测试。但我得到的只是“未捕获的类型错误:无法读取未定义的属性‘测试’”。 如何访问 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();

【问题讨论】:

  • 在上课时使用 : var root = self。在子方法之后使用 root.test()

标签: javascript node.js oop ssh2-sftp


【解决方案1】:

当使用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 的好文章。

【讨论】:

    【解决方案2】:

    当您将函数用作回调(将其作为参数传递给另一个函数)时,回调中的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();
    });
    

    如您所见,readdirCallback 中的this 看起来不再正确,该函数不是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 仍然可用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-07
      • 1970-01-01
      相关资源
      最近更新 更多