如何保持对正确对象的引用?

时间:2013-07-18 17:25:24

标签: javascript node.js reference socket.io

我有这样的代码:

for (var index = 1; index < args.length; index++) {
    var shell = args[index];
    listener.of('/' + shell.namespace || 'shotgun')
        .on('connection', function (socket) {
            socket.on('execute', function (cmdStr, context, options) {
                console.log('Received: ' + cmdStr);
                var result = shell.execute(cmdStr, context, options);
                socket.emit('result', result);
            });
        });
}

我正在使用socket.io,我正在创建多个名称空间。 socket.io命名空间工作得很好,但在execute回调中,对shell的引用始终是for循环中创建的最后一个对象。我需要循环的每次迭代来保持对该迭代的shell的引用。

3 个答案:

答案 0 :(得分:3)

嗯,最终的答案是使用let(ECMAScript 6或node --harmony):

for (let index = 1; index < args.length; index++) {
    let shell = args[index];
    // ...
}

与此同时,您可以使用closure或其他function范围来保留其他indexshell每次迭代:

function iterator(shell, index) {
    listener.of('/' + shell.namespace || 'shotgun')
        // ...
}

for (var index = 1; index < args.length; index++) {
    iterator(args[index], index);
}

而且,如果argsArray,也可以使用.forEach()来完成:

args.forEach(function (shell, index) {
    listener.of('/' + shell.namespace || 'shotgun')
        // ...
});

答案 1 :(得分:2)

以下是使用.bind进行挑战的解决方案之一。

for (var index = 1; index < args.length; index++) {
  var shell = args[index];
  listener.of('/' + shell.namespace || 'shotgun')
    .on('connection', function(socket) {
      shell = this.shell;
      socket.on('execute', function (cmdStr, context, options) {
        console.log('Received: ' + cmdStr);
        var result = shell.execute(cmdStr, context, options);
        socket.emit('result', result);
      });
    }.bind({ shell: shell }));
}

答案 2 :(得分:2)

问题是你正在创建一个引用变量shell的闭包,并在调用函数时评估变量,而不是在定义它时。您需要创建一个引用循环变量当前值的闭包。有几种方法,但一种方法是使用IIFE

for (var index = 1; index < args.length; index++) {
    var shell = args[index];
    listener.of('/' + shell.namespace || 'shotgun')
        .on('connection', (function (_shell) { return function (socket) {
            socket.on('execute', function (cmdStr, context, options) {
                console.log('Received: ' + cmdStr);
                var result = _shell.execute(cmdStr, context, options);
                socket.emit('result', result);
            }; }(shell)));
        });
}

注意:您可以使用相同的名称(shell)作为IIFE的正式参数,这将隐藏外部作用域中的变量,但我重命名为_shell以澄清发生了什么