函数,该函数只能调用一次

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

324168 次浏览
var quit = false;


function something() {
if(quit) {
return;
}
quit = true;
... other code....
}

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

用可重用的 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
}

如果你所说的“不会被执行”是指“不会在多次调用时执行任何操作”,那么你可以创建一个闭包:

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


something(); // "do something" happens
something(); // nothing happens

作为对@Vladloffe (现已删除)的评论的回应: 使用全局变量,其他代码可以重置“已执行”标志的值(无论您为其选择什么名称)。对于闭包,其他代码无法执行此操作,无论是偶然还是故意。

正如这里的其他答案所指出的,一些库(例如 下划线拉姆达)有一个小实用函数(通常命名为 once()[*]) ,它接受一个函数作为参数,并返回另一个函数,该函数只调用所提供的函数一次,而不管调用返回的函数多少次。返回的函数还缓存提供的函数首先返回的值,并在随后的调用中返回该值。

但是,如果您不使用这样的第三方库,但是仍然想要一个实用函数(而不是我上面提供的临时解决方案) ,那么实现起来非常容易。我见过的最好的版本是 这是 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;。一旦 fn被调用,闭包就没有理由维护对 context的引用。

用法:

function something() { /* do something */ }
var one_something = once(something);


one_something(); // "do something" happens
one_something(); // nothing happens

[ * ] < sub > 请注意,其他库,比如 JQuery 的 Drupal 扩展,可能有一个名为 once()的函数,它的功能完全不同。

试试这个

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

你可以简单地让函数“移除它自己”

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

来自一个叫克罗克福德的家伙

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

尝试使用下划线“ once”函数:

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

Http://underscorejs.org/#once

一旦 空荡荡的函数被调用,就指向它:

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)

下面是一个示例 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 或通过浏览器编写 JavaScript,请考虑 “一次”npm 模块:

var once = require('once')


function load (file, cb) {
cb = once(cb)
loader.load('file')
loader.once('load', cb)
loader.once('error', cb)
}
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; */
if (!window.doesThisOnce){
function myFunction() {
// do something
window.doesThisOnce = true;
};
};

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

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


once(); once();

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

once.done = false;

这对于防止无限循环很有用(使用 jQuery) :

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

如果您担心名称空间污染,可以用一个长的随机字符串替换“ doIt”。

它有助于防止粘性执行

var done = false;


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

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 的回答的变化

如果使用 Ramda,可以使用函数 “一次”

引自文件:

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

接受一个函数 fn 并返回一个函数,该函数保护 fn 的调用,这样不管调用返回的函数多少次,fn 都只能被调用一次。在后续调用中返回计算的第一个值。

var addOneOnce = R.once(x => x + 1);
addOneOnce(10); //=> 11
addOneOnce(addOneOnce(50)); //=> 11

如果您希望将来能够重用这个函数,那么基于 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!

简单的装饰,当你需要的时候很容易写

function one(func) {
return function () {
func && func.apply(this, arguments);
func = null;
}
}

使用:

var initializer= one( _ =>{
console.log('initializing')
})


initializer() // 'initializing'
initializer() // nop
initializer() // nop

尽可能简单

function sree(){
console.log('hey');
window.sree = _=>{};
}

你可以看到结果

script result

JQuery 只允许使用 一()方法调用函数一次:

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 方法 ()实现:

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>

把我的帽子扔在戒指的乐趣,增加了记忆的优势

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
...

一个只开一次灯的简单例子。

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 中的闭包造成的。

// This is how function in JavaScript can be called only once


let started = false;
if (!started) {
start() { // "do something" }
}
started = true;
}

你可以使用 IIFE。IIFE 表示立即调用函数表达式,其结果是在创建函数时只调用一次函数。 您的代码将是这样的:

(function () {
//The code you want to execute only one time etc...
console.log("Hello world");
})()

此外,这样函数中的数据仍然被封装。
当然,你也可以从函数中返回值,并将它们存储到一个新的变量中,方法是:

const/let value = (function () {
//The code you want to execute only one time etc...
const x = 10;
return x;
})()
function once (fn1) {
var ran = false
var memo = null
var fn = function(...args) {
if(ran) {return memo}
ran = true
memo = fn1.apply(null, args)
return memo
}
return fn
}

我使用打字机与节点,这是“我讨厌懒惰的回答,启发了我。”。我刚把函数分配给 Noop函数。

let printName = (name: string) => {
console.log(name)
printName = () => {}
}


printName('Sophia') // Sophia
printName('Nico')   // Nothing Happens

Https://jsbin.com/yuzicek/edit?js,console

事件处理程序

如果该函数是一个事件侦听器的回调函数,那么在 addEventListner方法中已经有一个内置选项,可以只执行 callback一次。

它可以接受3个参数

  • 类型
  • 复试
  • 选择

options是一个具有名为 once的属性的对象

例如:

const button = document.getElementById('button');


const callbackFunc = () => {
alert('run')
}


button.addEventListener('click', callbackFunc, { once: true }) 
<button id="button">Click Once</button>

function x()
{
let a=0;
return function check()
{
if(!a++)
{
console.log("This Function will execute Once.")
return;
}
console.log("You Can't Execute it For the Second Time.")
return;
}
}


z=x()
z() //Op - This Function will execute once
z() //OP - You can't Execute it for the second time.

我发现只有一个简单的函数只返回一次 true 是很有用的,这样你就可以把副作用保持在更高的水平。

let once = () => !! (once = () => false);


once() // true
once() // false

使用方法如下:

if (once()) {
sideEffect()
}

这利用了这样一个事实,即您可以强制赋值表达式返回 true,同时将相同的函数更改为返回 false的函数。

如果必须让它执行一个函数,可以使用三元函数对其进行调整:

let once = (x) => !! (once = () => false) ? x() : false;

现在它接受一个函数作为参数。有趣的是,第二个 false从未达到。