【问题标题】:JavaScript array/object of functions by reference引用的 JavaScript 数组/函数对象
【发布时间】:2013-03-04 12:46:06
【问题描述】:

给定:

function shout(){ alert('Hello!'); }
var dasarray = [ shout ];

shout();
dasarray[0]();

shout = function(){ alert('World!'); }

shout();
dasarray[0]();

输出:

Hello!

Hello!

World!

Hello!

我预计 dasarray 会收到对函数 shout 的引用,但遗憾的是第四个输出也是 hello。如果我假设正确,我能够正确修改 shout 函数,但这导致我假设该函数没有通过引用传递到 dasarray

我已经用一个对象尝试了这个例子,而不是一个数组:

dasarray = { myfunction: shout }

同样令人失望的结果。

我的意图是有一个数组/对象/具有按顺序运行并且可以实时扩展的函数。

例如,使用新功能扩展 JavaScript 代码并向以正确顺序运行的现有事件添加额外的函数调用。

那么,如何通过引用将函数放入数组/对象中?


感谢您的好答案。我只是想解释一下我选择了Eli's answer,因为它引导我进入这个设置:

zzz = {
    calls: [],
    shout: function(message) {
        alert('Shouting: ' + message);
    },
    initialize: function () {
        zzz.calls.push(['shout','Hello World']);
        zzz.calls.push(['shout','this is']);
        zzz.calls.push(['shout','my last shout!']);
        zzz.run();

        zzz.shout = function(){ alert('modified!'); };
        zzz.run();
    },
    run: function () {
        $.each(zzz.calls, function(){ zzz[this[0]](this[1]); }); // <- Using jQuery $.each here, just to keep it easy
    }
};

zzz.initialize();

【问题讨论】:

  • 是对函数的引用。您正在更改 shout 指向的内容,数组仍然引用相同的函数。

标签: javascript arrays function object pass-by-reference


【解决方案1】:

我希望 dasarray 收到对函数 shout 的引用

确实如此。它确实没有收到对变量shout的引用。 (在函数声明中,函数名称定义的符号实际上是一个变量——这就是为什么你可以稍后分配给它的原因。)所以你后面的行改变变量:

shout = function(){ alert('World!'); }

...对dasarray 中早期函数的引用没有影响。

将对象引用视为一个值,说明在哪里可以找到对象。当你这样做时:

function shout(){ alert('Hello!'); }

...符号shout 接收一个,说明该函数的位置,如下所示:

那么当你这样做时:

var dasarray = [ shout ];

...value 放在数组的第一个条目中。现在符号shoutdasarray 中的第一个条目都具有相同的值,这告诉JavaScript 引擎在内存中的哪里可以找到该函数对象。所以我们有这个:

但变量shoutdasarray 中的条目彼此之间没有任何联系。

然后你这样做:

shout = function(){ alert('World!'); }

...创建一个新函数并将一个新值存储在变量shout 中,说明该新函数在哪里。但这对存储在dasarray 的条目0 中的值没有影响。我们最终得到了这个:

我在上面说了很多“值”,因为这就是“对象引用”:一个值,就像值5。只是值的使用方式是查找一个对象在哪里。当您将该值从一个变量分配给另一个变量时,该值将被复制,就像将值 5 从一个变量复制到另一个变量时被复制一样。

我不能说我很喜欢Eli's workaround,我宁愿更直接地谈论它并以简单的方式使用对象:

var obj = {
    shout: function() { alert("Hello!"); }
};
var dasarray = [ obj ];

obj.shout();                               // Hello!
dasarray[0].shout();                       // Hello!

obj.shout = function() { alert("World"); };

obj.shout();                               // World!
dasarray[0].shout();                       // World!

【讨论】:

  • 感谢您的回答,这很清楚,但@EliGassert 也提供了一个非常好的解决方法:)
  • @FTav:很高兴有帮助。对 Eli 应有的尊重,但我认为有更好的方法来做到这一点。这比必要的复杂。 FWIW,我在上面给出了更直接的方法。
  • 对您的解决方案毫无疑虑。它很干净(尤其是新的编辑)。 +1 对您的回答。我的解决方案非常通用,不适合现实世界的场景。我想象另一层或两层抽象,将 dasarray 与调用者分开。否则,您甚至可以更直接地将global 更改为dasarray 并直接在数组中修改函数。但我想真正的解决方案会比我们给出的示例和我们提供的解决方案更复杂。
【解决方案2】:

我同意T.J.'s answer。但是,如果您想做某种解决方法,您可以创建一个始终从函数缓存中进行“及时”查找的函数。看到这个fiddle

var getFunctionRef = function(funcName)
{
    return function() { global[funcName](); };
}

var global = { };
var arr = [];

global.shout = function() { alert('hello'); }

arr[0] = getFunctionRef('shout');

global.shout = function() { alert('world'); }

arr[0]();

这是一个非常基本的例子。有更广泛的方法来做到这一点。但这应该证明这个概念。

【讨论】:

  • 谢谢 Eli,TJ 以非常好的方式解释了为什么这并不是真正的参考而不是通过值传递,但是您的解决方案也将我推向了解决我的问题的正确方向!
猜你喜欢
  • 2019-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-13
  • 1970-01-01
  • 1970-01-01
  • 2019-02-26
  • 1970-01-01
相关资源
最近更新 更多