it-swarm.com.de

Funktion in Javascript, die nur einmal aufgerufen werden kann

Ich muss eine Funktion erstellen, die nur einmal ausgeführt werden kann, in jedem Fall wird sie nach dem ersten Mal nicht ausgeführt. Ich kenne C++ und Java über statische Variablen, die die Arbeit erledigen können, aber ich möchte wissen, ob es einen eleganteren Weg gibt, dies zu tun?

98
vlio20

Wenn mit "wird nicht ausgeführt" gemeint ist, dass "bei mehrmaligem Aufruf nichts unternommen wird", können Sie einen Abschluss erstellen:

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

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

Antwort auf einen Kommentar von @Vladloffe (jetzt gelöscht): Mit einer globalen Variablen könnte ein anderer Code den Wert des "ausgeführten" Flags zurücksetzen (welcher Name auch immer Sie dafür wählen). Mit einer Schließung hat ein anderer Code weder aus Versehen noch absichtlich die Möglichkeit, dies zu tun.

Wie andere Antworten hier zeigen, haben mehrere Bibliotheken (wie nterstrich und Ramda ) eine kleine Utility-Funktion (normalerweise once() genannt).[*]), der eine Funktion als Argument akzeptiert und eine andere Funktion zurückgibt, die die angegebene Funktion genau einmal aufruft, unabhängig davon, wie oft die zurückgegebene Funktion aufgerufen wird. Die zurückgegebene Funktion speichert auch den Wert zwischen, der zuerst von der angegebenen Funktion zurückgegeben wurde, und gibt diesen bei nachfolgenden Aufrufen zurück.

Wenn Sie jedoch keine Bibliothek eines Drittanbieters verwenden und dennoch eine solche Utility-Funktion (anstelle der oben angebotenen Nonce-Lösung) wünschen, ist die Implementierung einfach genug. Die schönste Version, die ich gesehen habe, ist diese hier gepostet von David Walsh :

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

Ich würde gerne fn = null; In fn = context = null; Ändern. Es gibt keinen Grund für den Abschluss, einen Verweis auf context beizubehalten, sobald fn aufgerufen wurde.

[*]Beachten Sie jedoch, dass andere Bibliotheken, wie z. B. this Drupal Erweiterung auf jQuery , möglicherweise eine Funktion namens once() haben, die etwas ganz anderes bewirkt .

191
Ted Hopp

Ersetzen Sie es durch eine wiederverwendbare NOOP (keine Operation) - Funktion.

// 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
}
58
I Hate Lazy

Zeigen Sie auf eine leere Funktion, sobald diese aufgerufen wurde:

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>

Oder wie folgt:

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)
25
vsync

UnderscoreJs hat eine Funktion, die das macht, nderscorejs.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;
    };
  };
25
asawyer

Apropos statische Variablen, dies ist ein bisschen wie die Closure-Variante:

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

once(); once(); 

Sie können dann eine Funktion zurücksetzen, wenn Sie möchten:

once.done = false;
10
Bunyk
var quit = false;

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

Sie könnten einfach die Funktion "sich selbst entfernen" haben

​function Once(){
    console.log("run");

    Once = undefined;
}

Once();  // run
Once();  // Uncaught TypeError: undefined is not a function 

Dies ist jedoch möglicherweise nicht die beste Antwort, wenn Sie keine Fehler verschlucken möchten.

Sie könnten dies auch tun:

function Once(){
    console.log("run");

    Once = function(){};
}

Once(); // run
Once(); // nothing happens

Ich brauche es, um wie ein intelligenter Zeiger zu arbeiten. Wenn es keine Elemente vom Typ A gibt, kann es ausgeführt werden. Wenn es ein oder mehrere A-Elemente gibt, kann die Funktion nicht ausgeführt werden.

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

    // do stuff
}
3
Shmiddty

versuche dies

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

Von einem Typen namens Crockford ... :)

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

Wenn Sie die Funktion in Zukunft wiederverwenden möchten, funktioniert dies gut, basierend auf dem obigen Code von Ed Hopp (mir ist klar, dass die ursprüngliche Frage diese zusätzliche Funktion nicht erforderte!):

   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();

Die Ausgabe sieht folgendermaßen aus:

Hello World!
Reset
Hello World!
1
CMP

Wenn Sie Node.js verwenden oder JavaScript mit browserify schreiben, berücksichtigen Sie das "einmal" npm-Modul :

var once = require('once')

function load (file, cb) {
  cb = once(cb)
  loader.load('file')
  loader.once('load', cb)
  loader.once('error', cb)
}
1
orcaman

Hier ist ein Beispiel für JSFiddle - http://jsfiddle.net/6yL6t/

Und der Code:

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

Du könntest es tun:

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

Und es wird nur einmal ausgeführt :)

1
Aldekein

Ersteinrichtung:

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

Wiederverwendbare invalidate -Funktion, die mit setInterval funktioniert:

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

Probieren Sie es auf JSBin aus: https://jsbin.com/vicipar/edit?js,console

Variation von Antwort von Bunyk

1
user300375

Der Versuch, die Funktion "einmalig" zu verwenden:

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

http://underscorejs.org/#once

0
Andrew Feng

Wenn Sie Ramda verwenden, können Sie die Funktion "einmal" verwenden.

Ein Zitat aus der Dokumentation:

once Funktion (a… → b) → (a… → b) PARAMETER Hinzugefügt in v0.1.0

Akzeptiert eine Funktion fn und gibt eine Funktion zurück, die den Aufruf von fn so schützt, dass fn immer nur einmal aufgerufen werden kann, unabhängig davon, wie oft die zurückgegebene Funktion aufgerufen wird. Der erste berechnete Wert wird in nachfolgenden Aufrufen zurückgegeben.

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

einfacher dekorateur, der einfach zu schreiben ist, wenn man ihn braucht

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

mit:

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

initializer() // 'initializing'
initializer() // nop
initializer() // nop
0
pery mimon

halte es so einfach wie möglich

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

Sie können das Ergebnis sehen

script result

0
Shreeketh K
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; */
0
RegarBoy