JavaScript中的函数只能调用一次

我需要创build一个只能执行一次的函数,每次在第一个函数执行后都不会执行。 我从C ++和Java知道可以做这个工作的静态variables,但是我想知道是否有更好的方法来做到这一点?

如果通过“不会被执行”,你的意思是“多次调用时什么也不做”,你可以创build一个闭包:

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

在回答@Vladloffe(现在删除)的评论:其他代码可以重置“执行”标志的值(无论你select什么名字)的全局variables。 在closures的情况下,其他代码无意或故意地无法执行此操作。

正如这里的其他答案所指出的那样,一些库(比如Underscore和Ramda )有一个小函数函数(通常命名为once() [*] ),它接受一个函数作为参数,并返回另一个函数,无论返回的函数被调用多less次。 返回的函数还会caching由提供的函数返回的值,并在随后的调用中返回该值。

但是,如果你不使用这样的第三方库,但仍然需要这样一个实用程序function(而不是我上面提供的nonce解决scheme),实现起来很简单。 我见过的最好的版本是David Walsh发布的 :

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

但是请注意,其他库,比如这个用于jQuery的Drupal扩展 ,可能有一个名为once()的函数,它做了一些完全不同的事情。

将其replace为可重用的NOOP (无操作)function。

 // 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 } 

UnderscoreJs有一个这样的function, 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; }; }; 

一旦被调用,就指向一个空函数。

 var myFunc = function(){ myFunc = function(){}; // kill it as soon as it was called console.log('call once and never again!'); // your stuff here }; 

谈到静态variables,这有点像closuresvariables:

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

如果你愿意,你可以重置一个函数:

 once.done = false; 
 var quit = false; function something() { if(quit) { return; } quit = true; ... other code.... } 

你可以简单地使用“删除自己”

 ​function Once(){ console.log("run"); Once = undefined; } Once(); // run Once(); // Uncaught TypeError: undefined is not a function 

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

你也可以这样做:

 function Once(){ console.log("run"); Once = function(){}; } Once(); // run Once(); // nothing happens 

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

 function Conditional(){ if (!<no elements from type A>) return; // do stuff } 

从一些叫克罗克福德的家伙… 🙂

 function once(func) { return function () { var f = func; func = null; return f.apply( this, arguments ); }; } 

尝试这个

 var fun = (function() { var called = false; return function() { if (!called) { console.log("I called"); called = true; } } })() 

这里是一个例子JSFiddle – http://jsfiddle.net/6yL6t/

和代码:

 function hashCode(str) { var hash = 0, i, chr, len; if (str.length == 0) return hash; for (i = 0, len = str.length; i < len; i++) { chr = str.charCodeAt(i); hash = ((hash << 5) - hash) + chr; hash |= 0; // Convert to 32bit integer } return hash; } var onceHashes = {}; function once(func) { var unique = hashCode(func.toString().match(/function[^{]+\{([\s\S]*)\}$/)[1]); if (!onceHashes[unique]) { onceHashes[unique] = true; func(); } } 

你可以这样做:

 for (var i=0; i<10; i++) { once(function() { alert(i); }); } 

它只会运行一次:)

初始设置:

 var once = function( once_fn ) { var ret, is_called; // return new function which is our control function // to make sure once_fn is only called once: return function(arg1, arg2, arg3) { if ( is_called ) return ret; is_called = true; // return the result from once_fn and store to so we can return it multiply times: // you might wanna look at Function.prototype.apply: ret = once_fn(arg1, arg2, arg3); return ret; }; } 

如果您使用Node.js或用browserify编写JavaScript,请考虑“once”npm模块 :

 var once = require('once') function load (file, cb) { cb = once(cb) loader.load('file') loader.once('load', cb) loader.once('error', cb) } 

setInterval一起使用的可重用的invalidate函数:

 var myFunc = function (){ if (invalidate(arguments)) return; console.log('called once and never again!'); // your stuff here }; const invalidate = function(a) { var fired = a.callee.fired; a.callee.fired = true; return fired; } setInterval(myFunc, 1000); 

试试JSBin: https ://jsbin.com/vicipar/edit ? js,console

Bunyk的答案的变化

尝试使用下划线“一次”function:

 var initialize = _.once(createApplication); initialize(); initialize(); // Application is only created once. 

http://underscorejs.org/#once

 var init = function() { console.log("logges only once"); init = false; }; if(init) { init(); } /* next time executing init() will cause error because now init is -equal to false, thus typing init will return false; */ 

如果您使用拉姆达,您可以使用“一次”function。

来自文档的引用:

一次函数(a …→b)→(a …→b)参数在v0.1.0中添加

接受一个函数fn并返回一个函数来防止调用fn,这样fn只能被调用一次,不pipe调用了多less次函数。 计算出的第一个值在随后的调用中返回。

 var addOneOnce = R.once(x => x + 1); addOneOnce(10); //=> 11 addOneOnce(addOneOnce(50)); //=> 11 
 if (!window.doesThisOnce){ function myFunction() { // do something window.doesThisOnce = true; }; }; 

这对防止无限循环(使用jQuery)非常有用:

 <script> var doIt = true; if(doIt){ // do stuff $('body').html(String($('body').html()).replace("var doIt = true;", "var doIt = false;")); } </script> 

如果你担心命名空间污染,可以用一个长长的随机string来替代“doit”。

这有助于防止粘性执行

 var done = false; function doItOnce(func){ if(!done){ done = true; func() } setTimeout(function(){ done = false; },1000) }