是否可以在没有外部输入的情况下使功能自我感知

时间:2016-05-12 13:12:59

标签: javascript function

背景

我想要一个跟踪自己状态的函数:

var myObject = {

    myFunction: function () {

        var myself = this.myFunction;
        var firstTime = Boolean(!myself.lastRetry);

        if (firstTime) {

            myself.lastRetry = Date.now();
            return true;
        }

        // some more code

    }
}

上述代码的问题是this的值将取决于函数调用的站点。我希望函数能够在不使用的情况下引用自身:

  • myObject.myFunction
  • .bind()
  • .apply()
  • .call()

问题

是否有可能提供一种独立于其呼叫站点的这种自我意识功能,并且没有外部参考的任何帮助?

3 个答案:

答案 0 :(得分:8)

如果要将该状态存储在函数实例上,请为该函数指定一个名称,并在其中使用该名称:

var myObject = {

    myFunction: function theFunctionName() {
    //                   ^^^^^^^^^^^^^^^--------------------- name
        var firstTime = Boolean(!theFunctionName.lastRetry);
    //                           ^--------------------------- using it
        if (firstTime) {

            theFunctionName.lastRetry = Date.now();
    //      ^------------------------------------------------ using it
            return true;
        }

        // some more code

    }
};

每当你想要递归地使用函数时,你也会这样做。当您以某种方式为函数命名时(将名称放在function之后和(之前),该名称在函数自己的代码中是范围内的。 (如果它是一个函数表达式,它不在包含该函数的代码的范围内,但如果它是一个函数声明,那就是它。你的是一个表达式。)

这是一个命名函数表达式(之前你有一个匿名函数表达式)。您可能听到有关NFE的警告,但各种JavaScript实现与它们之间的问题基本上都是过去的。 (IE8仍然错误地处理它们:this post on my blog中的更多内容。)

你可以考虑通过IIFE将该状态保存在某个私密的地方:

var myObject = (function(){
    var lastRetry = null;
    return {
        myFunction: function() {
            var firstTime = Boolean(!lastRetry);
            if (firstTime) {

                lastRetry = Date.now();
                return true;
            }

            // some more code

        }
    };
})();

现在,外部匿名函数之外的任何内容都看不到lastRetry。 (如果你支持顽固的XP用户,你不必担心IE8。:-))

附注:一元!运算符始终返回一个布尔值,所以你的

var firstTime = Boolean(!theFunctionName.lastRetry);

......完全等同于:

var firstTime = !theFunctionName.lastRetry;

...但是有一个额外的不必要的函数调用。 (不是它会伤害任何东西。)

答案 1 :(得分:0)

当然你可以简单地给你的函数一个内部命名表示,它可以从那里引用它自己。例如......

var obj = {
    doThings:function doThingsInternal(arg1, arg2) {
        console.log(arg1, arg2);
        for (var arg in doThingsInternal.arguments) {
            console.log(arg);
        }
    }
};

obj.doThings('John', 'Doe');

答案 2 :(得分:0)

如果你不太愿意在函数中保持状态存在知识,你可以使用一个简单的闭包。但我猜你不想那样。另一种方法是在第一次调用时更改函数本身。好处,不需要/更少的状态变量,并且不会对后续调用进行昂贵的检查! -

    var myObject = {

    myFunction: function () {
       // Whatever you wanna do on the first call...
       // ...
       // And then...
       this.myFunction = function(){
         // Change the definition to whatever it should do
         // in the subsequent calls.
       }
       // return the first call value.
    }
};

您可以通过更改您所在州的功能定义,将此模型扩展到任何状态。