回答:
「実行されない」という意味で「複数回呼び出されても何もしない」という意味の場合は、クロージャーを作成できます。
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()
)には、関数を引数として受け入れ、指定された関数を1回だけ呼び出す別の関数を返す)があります。多くの場合、返された関数が呼び出されます。返された関数は、指定された関数によって最初に返された値もキャッシュし、後続の呼び出しでそれを返します。
ただし、そのようなサードパーティのライブラリを使用していないが、そのようなユーティリティ関数(上記で提供したnonceソリューションではなく)が必要な場合は、簡単に実装できます。私が見た中で最も素晴らしいバージョンは、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
呼び出さ。
[*] ただし、このjQueryのDrupal拡張などの他のライブラリには、once()
まったく異なる機能を実行するという名前の関数がある場合があることに注意してください。
再利用可能な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
}
setInterval(foo, 1000)
-そして、これはすでに機能しなくなりました。現在のスコープの参照を上書きしているだけです。
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>
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)
setInterval()
)、参照は呼び出されたときに元の機能を繰り返すことです。
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;
};
};
once
引数を受け入れるのは私にはおかしいようです。あなたはそうすることができてsquareo = _.once(square); console.log(squareo(1)); console.log(squareo(2));
、1
両方の呼び出しのために得ることができますsquareo
。私はこの権利を理解していますか?
_.once
メソッドの使用を勧めません。jsfiddle.net/631tgc5f/1を
_
。このような小さなコードをライブラリ全体に依存することはお勧めしません。
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
スマートポインターのように機能させる必要があります。タイプAの要素が存在しない場合は実行でき、1つ以上のA要素がある場合は関数を実行できません。
function Conditional(){
if (!<no elements from type A>) return;
// do stuff
}
Once
コールバックとして渡された場合(たとえばsetInterval(Once, 100)
)、これは機能しません。元の関数は引き続き呼び出されます。
これを試して
var fun = (function() {
var called = false;
return function() {
if (!called) {
console.log("I called");
called = true;
}
}
})()
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);
JSBinで試してください: https
ここにJSFiddleの例があります- :
そしてコード:
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を作成している場合は、「1回」のnpmモジュールを検討してください。
var once = require('once')
function load (file, cb) {
cb = once(cb)
loader.load('file')
loader.once('load', cb)
loader.once('error', cb)
}
将来的に関数を再利用できるようにしたい場合、これは上記の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!
アンダースコアの「1回」関数を使用しようとしています:
var initialize = _.once(createApplication);
initialize();
initialize();
// Application is only created once.
できるだけシンプルにしてください
function sree(){
console.log('hey');
window.sree = _=>{};
}
結果を見ることができます
this
代わりに使用してくださいwindow
jQueryでは、メソッドone()を使用して関数を1回だけ呼び出すことができます。
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>
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>
名前空間の汚染が心配な場合は、「doIt」を長くランダムな文字列に置き換えてください。