javascript中的函数只能被调用一次

vli*_*o20 104 javascript design-patterns function

我需要创建一个只能执行一次的函数,每次执行后都不会执行.我从C++和Java中了解到可以完成工作的静态变量,但我想知道是否有更优雅的方法来做到这一点?

Ted*_*opp 198

如果"不会执行"你的意思是"在多次调用时不会做什么",你可以创建一个闭包:

var something = (function() {
    var executed = false;
    return function() {
        if (!executed) {
            executed = true;
            // do something
        }
    };
})();

something(); // "do something" happens
something(); // nothing happens
Run Code Online (Sandbox Code Playgroud)

回答@Vladloffe的评论(现已删除):使用全局变量,其他代码可以重置"已执行"标志的值(无论你为它选择什么名称).有了封闭,其他代码无法做到这一点,无论是意外还是故意.

正如其他答案所指出的,一些库(如UnderscoreRamda)有一个小实用函数(通常名为once()[*]),它接受一个函数作为参数,并返回另一个函数,它只调用一次提供的函数,无论如何很多次调用返回的函数.返回的函数还会缓存由提供的函数首先返回的值,并在后续调用中返回该值.

但是,如果您没有使用这样的第三方库,但仍然需要这样的实用程序功能(而不是我上面提供的nonce解决方案),那么实现起来就很容易了.我见过的最好的版本是David Walsh发布的这个版本:

function once(fn, context) { 
    var result;
    return function() { 
        if (fn) {
            result = fn.apply(context || this, arguments);
            fn = null;
        }
        return result;
    };
}
Run Code Online (Sandbox Code Playgroud)

我会倾向于改变fn = null;fn = context = null;.有没有理由,关闭,保持一个参考context一旦fn被调用.

[*]但是 要注意,其他库,例如对jQuery的这个Drupal扩展,可能有一个名为的函数once(),它做了一些完全不同的事情.

  • @EgyCode - 这在 [MDN 闭包文档](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) 中有很好的解释。 (2认同)
  • @EgyCode - 在某些上下文中(如在 `if` 语句测试表达式中),JavaScript 期望值为 `true` 或 `false` 之一,并且程序流根据表达式计算时找到的值做出反应。像 `==` 这样的条件运算符总是计算出一个布尔值。变量也可以包含“true”或“false”。(有关更多信息,请参阅 [boolean](https://developer.mozilla.org/en-US/docs/Glossary/Boolean)、[truthy](https://developer.mozilla.org/en- US/docs/Glossary/Truthy) 和 [falsey](https://developer.mozilla.org/en-US/docs/Glossary/Falsy)。 (2认同)

I H*_*azy 58

用可重复使用的NOOP (无操作)功能替换它.

// this function does nothing
function noop() {};

function foo() {
    foo = noop; // swap the functions

    // do your thing
}

function bar() {
    bar = noop; // swap the functions

    // do your thing
}
Run Code Online (Sandbox Code Playgroud)

  • @fableal:这不优雅怎么样?同样,它非常干净,需要的代码更少,并且不需要为每个应该禁用的函数添加新变量.A*"noop"*完全针对这种情况而设计. (11认同)
  • 不是最好的解决方案.如果您将此函数作为回调函数传递,则仍可多次调用它.例如:`setInterval(foo,1000)` - 已经不再适用了.您只是覆盖当前范围中的引用. (7认同)
  • 根据asawyer的响应,你只需要做_.once(foo)或_.once(bar),而且函数本身不需要知道只运行一次(不需要noop而且不需要*= noop). (2认同)

vsy*_*ync 27

一旦被调用,指向函数:

function myFunc(){
     myFunc = function(){}; // kill it as soon as it was called
     console.log('call once and never again!'); // your stuff here
};
Run Code Online (Sandbox Code Playgroud)
<button onClick=myFunc()>Call myFunc()</button>
Run Code Online (Sandbox Code Playgroud)

  • 这个问题是如果某个地方有另一个函数引用(例如它作为参数传递并隐藏在某个地方的另一个变量中 - 就像调用`setInterval()`那么)引用将重复原始功能调用. (5认同)
  • 该解决方案更符合 Javascript 等高度动态语言的精神。为什么要设置信号量,一旦函数被使用就可以简单地清空函数? (2认同)

asa*_*yer 25

UnderscoreJs有一个函数可以做到这一点,underscorejs.org/#once

  // Returns a function that will be executed at most one time, no matter how
  // often you call it. Useful for lazy initialization.
  _.once = function(func) {
    var ran = false, memo;
    return function() {
      if (ran) return memo;
      ran = true;
      memo = func.apply(this, arguments);
      func = null;
      return memo;
    };
  };
Run Code Online (Sandbox Code Playgroud)


Bun*_*nyk 10

谈到静态变量,这有点像闭包变体:

var once = function() {
    if(once.done) return;
    console.log('Doing this once!');
    once.done = true;
};

once(); once(); 
Run Code Online (Sandbox Code Playgroud)

如果您愿意,您可以重置一个功能:

once.done = false;
Run Code Online (Sandbox Code Playgroud)


Shm*_*dty 6

您可以简单地使用“删除自身”功能

\n\n
\xe2\x80\x8bfunction Once(){\n    console.log("run");\n\n    Once = undefined;\n}\n\nOnce();  // run\nOnce();  // Uncaught TypeError: undefined is not a function \n
Run Code Online (Sandbox Code Playgroud)\n\n

但如果您不想吞下错误,这可能不是最好的答案。

\n\n

你也可以这样做:

\n\n
function Once(){\n    console.log("run");\n\n    Once = function(){};\n}\n\nOnce(); // run\nOnce(); // nothing happens\n
Run Code Online (Sandbox Code Playgroud)\n\n

我需要它像智能指针一样工作,如果没有类型 A 的元素,则可以执行它,如果有一个或多个 A 元素,则函数无法执行。

\n\n
function Conditional(){\n    if (!<no elements from type A>) return;\n\n    // do stuff\n}\n
Run Code Online (Sandbox Code Playgroud)\n


Dio*_*ane 5

var quit = false;

function something() {
    if(quit) {
       return;
    } 
    quit = true;
    ... other code....
}
Run Code Online (Sandbox Code Playgroud)