将两个匿名函数解析为相同的定义点?

时间:2011-07-11 19:50:01

标签: javascript

我有以下形式的代码,用户可以在其中指定稍后将调用的回调:

var _deferred = [];

var deferred = function(callback) {
    _deferred.push(callback);
}

var doDeferred = function() {
    for(var i = 0, max = _deferred.length; i < max; i++) {
        _deferred[i].call();
    }
}

for(var i = 0; i < 5; i++) {
    deferred(function() {
        console.log("Some deferred stuff");
    });
}

doDeferred();

我想要认识到为deferred()指定的回调是一个解析为相同原点的匿名函数,并且只允许它添加一次。 Aka位于底部for循环中,当i = 1时会抛出异常。

像:

var deferred = function(callback) {
        if(_deferred.indexOf(callback) !== -1) {
                throw "Already added!";
        }
        _deferred.push(callback);
}

我可以通过添加“密钥”来想到许多方法,但我想知道我是否可以使用Function.caller的内容来创建“源哈希”?

有没有解决方案,我已经没有看到了?我真的更愿意接受这种负担,而不是将其推迟给延期的来电者并让他们提供某种独特的身份。

编辑:

澄清任何混淆。

是每次对deferred的调用都是一个唯一的函数对象,有自己的闭包等。因此我的indexOf总是会失败。这不是一个混乱点。

问题是这些匿名函数是在同一个地方声明的,它们是相同的代码,我该如何判断呢?我想确定声明性相等,而不是实例相等。我以为我可以以某种方式创建一个基于延迟调用者的哈希...

结论:

谢谢大家,好像这里没有真正优雅的解决方案。 toString方法不是确定的(具有相同主体的不同函数将与字符串一样测试) - 并且只是丑陋。我要把负担放在打电话上。

4 个答案:

答案 0 :(得分:1)

据我所知,如果你有两个具有相同实体的匿名函数,它们在“==”运算符方面就不相同,所以我认为你不能做indexOf()。< / p>

您可以检查新功能是否与阵列中已有的功能相同。要做到这一点,只需将函数转换为字符串并检查是否相等:

String((function(){/*something*/})) == String((function(){/*something*/}))

应该返回true;

答案 1 :(得分:1)

var deferred = function(callback) {
    if(_deferred.some(function(c){return c.toString() === callback.toString()})) {
            throw "Already added!";
    }
    _deferred.push(callback);
}

这将在第一次添加重复方法签名时抛出错误。

答案 2 :(得分:1)

问题是,在底部的循环中,它们不同的功能,所以公平地说它们都应该包括在内(老实说,不能保证两个函数的值都赢了根据当前存在的变量而不同。我也不确定'仅限于独特的功能'是人们所期望的,所以它可能导致大量的“调试”

这不是ECMAScript所要求的,但Function.toString()通常会返回其内部结构。所以你可能想要:

var ids = [] // separate ID takes up slightly more space, but lookup should 
             // be faster.
var deferred = function(callback) {
        var cbs = callback.toString() // or String(callback)
        if(ids.indexOf( cbs ) !== -1)
        {
                throw "Already added!";
        }
        ids.push( cbs )
        _deferred.push(callback);
}

如果您愿意使用for ... in循环:

var _deferred = {}
var deferred = function(callback) {
        var cbs = callback.toString() // or String(callback)
        if( _deferred[ cbs] )
        {
                throw "Already added!";
        }
        _deferred[ cbs] = callback;
}

// caution, this executes in arbitrary order.
var doDeferred = function() {
    for(var i in _deferred) {
        _deferred[i].call();
    }
}

答案 3 :(得分:1)

虽然我不会认为这很优雅,但你可以使用他们的toString()方法来比较匿名函数。

var deferred = function(callback) {
        var str = callback.toString();
        for var i = 0; i < _deferred.length; i++) {
            if (_deferred[i].toString() == str) {
                throw "Already added!";
            }
        }
        _deferred.push(callback);
}