【问题标题】:How can I keep track of multiple runs of the same function?如何跟踪同一函数的多次运行?
【发布时间】:2011-02-04 01:25:36
【问题描述】:

我有这样的功能:

function run(arg) {
    if (!window.alreadyRun) init();
    window.alreadyRun = true;
    /* more code */
}

你明白了,我想弄清楚这是不是第一次调用函数。

有没有更好的方法来做到这一点?不使用全局变量?像这样的:

function run(arg) {
    var ranAlready;
    if (!ranAlready) init();
    ranAlready = true;
    /* more code */
}

【问题讨论】:

    标签: javascript function


    【解决方案1】:

    这将返回一个函数,其中包含一个名为runCount 的变量,该变量将保存它被调用的次数。

    var yourFunction = function() {
        var runCount = 0;
    
        return function() {
            console.log(runCount);
            runCount++;
        }  
    
    }
    
    var a = yourFunction();
    
    a(); // runCount: 0
    a(); // runCount: 1
    a(); // runCount: 2
    a(); // runCount: 3
    

    See it on jsFiddle.

    如果你只是想运行一个初始化类型的函数,你可以将代码放在上面返回内部函数。它会在返回内部函数之前被调用一次,并且它的作用域将保留在它的外部函数中。

    【讨论】:

    • 你的意思是 var runCount = 0; 对吗?否则它是一个全球性的。也适用于 var 。惊人的。粉笔一记关闭
    • @qwertymk 我确实有var - 它将其范围设置为yourFunction。如果我在内部函数中使用它,它会重置它的作用域并且它是无用的(总是0)。
    • 太棒了,正是我想要的!
    • 好吧,你确实回答了我问的问题,只是不是我想问的问题。我转发了我想要的here
    【解决方案2】:

    闭包的力量。

    var f = (function(run) {
        return function() {
            if (!run) init(),run=true;
            // do code
        };
    }(false));
    

    如果您希望在下一次函数调用中再次调用它,您甚至可以使用 if (!run) init() && run = true 并获取 init 以返回 false

    我们有一个自执行函数,它创建一个本地 run 变量并通过将其作为参数传入将其设置为 false。然后,我们有一行检查它是否为 false,如果是,则为 init(), run=true,它正在运行 init 函数并在单个表达式中将其分配为 true。

    基本上,您在任何地方都使用全局作用域使变量成为函数的静态变量,您可以改为使用闭包作为局部函数作用域和全局作用域之间的作用域级别。

    如果您需要一个对函数来说是静态且只读的变量,您可以使用鲜为人知的 const 关键字。

    【讨论】:

    • if (!run) init(),run=true; 可以吗?以前从未见过这样的 JavaScript 代码。
    • @Alex 让我重复 a,b 语句会破坏可读性,我手动检查它的每次使用以查看它是否有效,因为我真的不信任它。
    • 是的,bclary.com/2004/11/07/#a-11.14 简单地说,引擎计算每个用逗号分隔的表达式并返回最右边的值(在这种情况下无关紧要,因为 run=true 的结果未分配)。在这种情况下,if(!run) { init(); run=true; } 是等价的。
    • @harnish 除了它的使用主要在单行中,如果你想避免使用大括号。
    • @Hamish @Raynos 谢谢大家。我不确定我是否会开始使用它,但知道总是很好:)
    【解决方案3】:

    我认为闭包对此完全是矫枉过正,只会使代码复杂化。

    您所描述的在面向对象的语言中称为静态变量,并且可以通过将属性直接附加到函数来在 JS 中很容易地模仿它。这是可能的,因为函数是 JS 中的一等对象:

    function run(arg) {
        if (!run.ranAlready) { // run.ranAlready is undefined at first, so falsy
           run.ranAlready = true;
           init();
        }
    
        /* more code */
    }
    

    这比嵌套函数要简单得多,你可以继续以完全相同的方式使用run()

    另一个优点是,对于单元测试,您仍然可以从函数外部访问 ranAlready 属性以检查您的代码是否正常工作:

    assert(run.runAlready == false);
    run();
    assert(run.runAlready === true);
    

    当然,这不能用于匿名函数,例如在事件处理程序中,但是为匿名函数命名而不是使用嵌套函数和额外的函数不是更简洁函数调用?

    【讨论】:

      【解决方案4】:

      这只是另一种方法。您可以让函数自行修改。在下面的例子中,myfunction 被更改为一个新的。这可能不是你正在寻找的东西,但我认为至少发布这个很有用,这样你就可以看到做事的替代方法(而且:自我修改代码有时会很酷)。

      var myfunction = function() {
          alert("This is the first time I'm executed");
      
          myfunction = function() {
              alert('Subsequent times');
          }
      }
      
      myfunction();  // displays the alert 'This is the first time...'
      myfunction();  // displays the alert 'Subsequent times'
      myfunction();
      

      示例:http://jsfiddle.net/jonathon/wntmB/

      【讨论】:

      • 在使用无法真正访问自身的匿名函数时,这样做很痛苦。 IE。将匿名函数作为参数传递给attachEvent
      • @Raynos 绝对 - 我不会推荐它用于那种事情。在你和亚历克斯的回答中,我并不认为它是最好的。我只是认为了解另一种技术很有用:)
      • 这是一种很好的技术,尤其是如果函数在每次调用时都发生了一些不同的变化;)
      猜你喜欢
      • 2011-06-21
      • 1970-01-01
      • 2021-12-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-24
      相关资源
      最近更新 更多