JavaScript 中只能调用一次的函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12713564/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Function in JavaScript that can be called only once
提问by vlio20
I need to create a function which can be executed only once, in each time after the first it won't be executed. I know from C++ and Java about static variables that can do the work but I would like to know if there is a more elegant way to do this?
我需要创建一个只能执行一次的函数,在第一次之后的每次都不会执行。我从 C++ 和 Java 知道可以完成这项工作的静态变量,但我想知道是否有更优雅的方法来做到这一点?
回答by Ted Hopp
If by "won't be executed" you mean "will do nothing when called more than once", you can create a closure:
如果“不会被执行”是指“多次调用时不会执行任何操作”,则可以创建一个闭包:
var something = (function() {
var executed = false;
return function() {
if (!executed) {
executed = true;
// do something
}
};
})();
something(); // "do something" happens
something(); // nothing happens
In answer to a comment by @Vladloffe (now deleted): With a global variable, other code could reset the value of the "executed" flag (whatever name you pick for it). With a closure, other code has no way to do that, either accidentally or deliberately.
回答@Vladloffe 的评论(现已删除):使用全局变量,其他代码可以重置“已执行”标志的值(无论您为它选择什么名称)。使用闭包,其他代码无法做到这一点,无论是意外还是故意。
As other answers here point out, several libraries (such as Underscoreand Ramda) have a little utility function (typically named once()
[*]) that accepts a function as an argument and returns another function that calls the supplied function exactly once, regardless of how many times the returned function is called. The returned function also caches the value first returned by the supplied function and returns that on subsequent calls.
正如这里的其他答案所指出的那样,一些库(例如Underscore和Ramda)有一个小实用函数(通常名为once()
[*]),它接受一个函数作为参数并返回另一个函数,该函数只调用一次提供的函数,无论如何多次调用返回的函数。返回的函数还缓存由提供的函数首先返回的值,并在后续调用中返回该值。
However, if you aren't using such a third-party library, but still want such a utility function (rather than the nonce solution I offered above), it's easy enough to implement. The nicest version I've seen is this one posted by David Walsh:
但是,如果您没有使用这样的第三方库,但仍然想要这样的实用函数(而不是我上面提供的 nonce 解决方案),那么实现起来就很容易了。我见过的最好的版本是David Walsh 发布的这个版本:
function once(fn, context) {
var result;
return function() {
if (fn) {
result = fn.apply(context || this, arguments);
fn = null;
}
return result;
};
}
I would be inclined to change fn = null;
to fn = context = null;
. There's no reason for the closure to maintain a reference to context
once fn
has been called.
我倾向于fn = null;
改为fn = context = null;
. 没有理由让闭包保持对context
曾经fn
被调用过的引用。
[*]Be aware, though, that other libraries, such as this Drupal extension to jQuery, may have a function named once()
that does something quite different.
[*]不过,请注意,其他库,例如jQuery 的 Drupal 扩展,可能有一个名为的函数once()
,它的功能完全不同。
回答by I Hate Lazy
Replace it with a reusable NOOP (no operation)function.
将其替换为可重复使用的 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
}
回答by vsync
Point to an emptyfunction once it has been called:
调用后指向一个空函数:
function myFunc(){
myFunc = function(){}; // kill it as soon as it was called
console.log('call once and never again!'); // your stuff here
};
<button onClick=myFunc()>Call myFunc()</button>
Or, like so:
或者,像这样:
var myFunc = function func(){
if( myFunc.fired ) return;
myFunc.fired = true;
console.log('called once and never again!'); // your stuff here
};
// even if referenced & "renamed"
((refToMyfunc)=>{
setInterval(refToMyfunc, 1000);
})(myFunc)
回答by asawyer
UnderscoreJs has a function that does that, underscorejs.org/#once
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;
};
};
回答by Bunyk
Talking about static variables, this is a little bit like closure variant:
说到静态变量,这有点像闭包变体:
var once = function() {
if(once.done) return;
console.log('Doing this once!');
once.done = true;
};
once(); once();
You could then reset a function if you wish:
如果你愿意,你可以重置一个函数:
once.done = false;
回答by Diodeus - James MacFarlane
var quit = false;
function something() {
if(quit) {
return;
}
quit = true;
... other code....
}
回答by Shmiddty
You could simply have the function "remove itself"
您可以简单地使用“删除自身”功能
?function Once(){
console.log("run");
Once = undefined;
}
Once(); // run
Once(); // Uncaught TypeError: undefined is not a function
But this may not be the best answer if you don't want to be swallowing errors.
但是,如果您不想吞下错误,这可能不是最佳答案。
You could also do this:
你也可以这样做:
function Once(){
console.log("run");
Once = function(){};
}
Once(); // run
Once(); // nothing happens
I need it to work like smart pointer, if there no elements from type A it can be executed, if there is one or more A elements the function can't be executed.
我需要它像智能指针一样工作,如果没有类型 A 的元素可以执行,如果有一个或多个 A 元素,则无法执行该函数。
function Conditional(){
if (!<no elements from type A>) return;
// do stuff
}
回答by Jowen
From some dude named Crockford... :)
来自一些名叫克罗克福德的家伙...... :)
function once(func) {
return function () {
var f = func;
func = null;
return f.apply(
this,
arguments
);
};
}
回答by Database_Query
try this
尝试这个
var fun = (function() {
var called = false;
return function() {
if (!called) {
console.log("I called");
called = true;
}
}
})()
回答by user300375
Reusable invalidate
function which works with setInterval
:
可重用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);
Try it on JSBin: https://jsbin.com/vicipar/edit?js,console
在 JSBin 上试试:https://jsbin.com/vicipar/edit ?js,console
Variation of answer from Bunyk