我试图在同一个类的方法连接中调用方法测试。但我得到的只是" 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();

答案 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
对象。
最简单的解决方案是对代码中的client
和username
变量执行相同的操作 - 将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
仍可用。