我需要创建一个只能执行一次的函数,每次执行后都不会执行。我从C ++和Java中了解到可以完成工作的静态变量,但我想知道是否有更优雅的方法来做到这一点?
答案 0 :(得分:187)
如果“不会被执行”你的意思是“在多次调用时不会做什么”,你可以创建一个闭包:
var something = (function() {
var executed = false;
return function() {
if (!executed) {
executed = true;
// do something
}
};
})();
something(); // "do something" happens
something(); // nothing happens
回答@Vladloffe的评论(现已删除):使用全局变量,其他代码可以重置“已执行”标志的值(无论您为其选择什么名称)。有了封闭,其他代码无法做到这一点,无论是意外还是故意。
正如其他答案所指出的,一些库(例如Underscore和Ramda)具有一点实用功能(通常名为once()
[*] )接受函数作为参数并返回另一个函数,该函数只调用一次提供的函数,无论调用返回函数多少次。返回的函数还会缓存由提供的函数首先返回的值,并在后续调用中返回该值。
但是,如果您没有使用这样的第三方库,但仍然需要这样的实用程序功能(而不是我上面提供的nonce解决方案),那么实现起来就很容易了。我见过的最好的版本是this one posted by David Walsh:
function once(fn, context) {
var result;
return function() {
if (fn) {
result = fn.apply(context || this, arguments);
fn = null;
}
return result;
};
}
我倾向于将fn = null;
更改为fn = context = null;
。一旦调用context
,关闭就没有理由保持对fn
的引用。
[*] 但请注意,其他库(例如this Drupal extension to jQuery)可能有一个名为once()
的函数,它可以完成不同的操作。< /子>
答案 1 :(得分: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
}
答案 2 :(得分: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;
};
};
答案 3 :(得分:21)
function myFunc(){
myFunc = function(){}; // kill it as soon as it was called
console.log('call once and never again!'); // your stuff here
};
&#13;
<button onClick=myFunc()>Call myFunc()</button>
&#13;
答案 4 :(得分:9)
谈论静态变量,这有点像闭包变体:
var once = function() {
if(once.done) return;
console.log('Doing this once!');
once.done = true;
};
once(); once();
如果您愿意,可以重置一个功能:
once.done = false;
答案 5 :(得分:4)
你可以简单地使用“自我删除”功能
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
我需要它像智能指针一样工作,如果没有类型A的元素可以执行,如果有一个或多个A元素,则无法执行该函数。
function Conditional(){
if (!<no elements from type A>) return;
// do stuff
}
答案 6 :(得分:4)
var quit = false;
function something() {
if(quit) {
return;
}
quit = true;
... other code....
}
答案 7 :(得分:2)
试试这个
var fun = (function() {
var called = false;
return function() {
if (!called) {
console.log("I called");
called = true;
}
}
})()
答案 8 :(得分:2)
来自一些名叫Crockford的家伙... :)
function once(func) {
return function () {
var f = func;
func = null;
return f.apply(
this,
arguments
);
};
}
答案 9 :(得分:1)
如果您希望将来能够重复使用该功能,那么这可以很好地基于上面的ed Hopp代码(我意识到原始问题没有要求这个额外的功能!):
var something = (function() {
var executed = false;
return function(value) {
// if an argument is not present then
if(arguments.length == 0) {
if (!executed) {
executed = true;
//Do stuff here only once unless reset
console.log("Hello World!");
}
else return;
} else {
// otherwise allow the function to fire again
executed = value;
return;
}
}
})();
something();//Hello World!
something();
something();
console.log("Reset"); //Reset
something(false);
something();//Hello World!
something();
something();
输出如下:
Hello World!
Reset
Hello World!
答案 10 :(得分:1)
可与invalidate
一起使用的setInterval
函数:
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);
的变化
答案 11 :(得分:1)
如果您使用Node.js或使用browserify编写JavaScript,请考虑"once" npm module:
var once = require('once')
function load (file, cb) {
cb = once(cb)
loader.load('file')
loader.once('load', cb)
loader.once('error', cb)
}
答案 12 :(得分:1)
初始设置:
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;
};
}
答案 13 :(得分:1)
这是一个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);
});
}
它只会运行一次:)
答案 14 :(得分:0)
把帽子戴在戒指上很有趣,增加了记忆的优点
const callOnce = (fn, i=0, memo) => () => i++ ? memo : (memo = fn());
// usage
const myExpensiveFunction = () => { return console.log('joe'),5; }
const memoed = callOnce(myExpensiveFunction);
memoed(); //logs "joe", returns 5
memoed(); // returns 5
memoed(); // returns 5
...
答案 15 :(得分:0)
jQuery只能使用方法one()调用一次函数:
let func = function() {
console.log('Calling just once!');
}
let elem = $('#example');
elem.one('click', func);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<p>Function that can be called only once</p>
<button id="example" >JQuery one()</button>
</div>
使用JQuery方法on()的实现:
let func = function(e) {
console.log('Calling just once!');
$(e.target).off(e.type, func)
}
let elem = $('#example');
elem.on('click', func);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<p>Function that can be called only once</p>
<button id="example" >JQuery on()</button>
</div>
使用本机JS的实现:
let func = function(e) {
console.log('Calling just once!');
e.target.removeEventListener(e.type, func);
}
let elem = document.getElementById('example');
elem.addEventListener('click', func);
<div>
<p>Functions that can be called only once</p>
<button id="example" >ECMAScript addEventListener</button>
</div>
答案 16 :(得分:0)
保持尽可能简单
function sree(){
console.log('hey');
window.sree = _=>{};
}
您可以看到结果
答案 17 :(得分:0)
我带有简单的装饰器,可以轻松解决您的问题
function one(func) {
return function () {
func && func.apply(this, arguments);
func = null;
}
}
使用:
var initializer= one( _ =>{
console.log('initializing')
})
initializer() // 'initializing'
initializer() // nop
initializer() // nop
答案 18 :(得分:0)
仅打开一次灯的简单示例。
function turnOnLightOnce() {
let lightOn = false;
return function () {
if (!lightOn) {
console.log("Light is not on...Turning it on for first and last time");
lightOn = true;
}
};
}
const lightOn = turnOnLightOnce();
lightOn() // Light is not on...Turning it on for first and last time
lightOn()
lightOn()
lightOn()
lightOn()
https://codesandbox.io/s/javascript-forked-ojo0i?file=/index.js
这是由于 JavaScript 中的闭包造成的。
答案 19 :(得分:0)
如果您正在使用Ramda,则可以使用函数"once"。
文件引用:
一旦功能 (a ...→b)→(a ...→b) 参数 在v0.1.0中添加
接受函数fn并返回一个保护fn调用的函数,这样无论调用返回函数多少次,fn只能被调用一次。计算的第一个值在后续调用中返回。
var addOneOnce = R.once(x => x + 1);
addOneOnce(10); //=> 11
addOneOnce(addOneOnce(50)); //=> 11
答案 20 :(得分:0)
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; */
答案 21 :(得分:0)
尝试使用下划线“一次”功能:
var initialize = _.once(createApplication);
initialize();
initialize();
// Application is only created once.
答案 22 :(得分:-1)
if (!window.doesThisOnce){
function myFunction() {
// do something
window.doesThisOnce = true;
};
};
答案 23 :(得分:-2)
有助于防止粘性执行
var done = false;
function doItOnce(func){
if(!done){
done = true;
func()
}
setTimeout(function(){
done = false;
},1000)
}
答案 24 :(得分:-2)
这个用于防止无限循环(使用jQuery):
<script>
var doIt = true;
if(doIt){
// do stuff
$('body').html(String($('body').html()).replace("var doIt = true;",
"var doIt = false;"));
}
</script>
如果您担心命名空间污染,请为“doIt”替换一个长的随机字符串。