Funkcja w javascript, którą można wywołać tylko raz

Muszę utworzyć funkcję, która może być wykonana tylko raz, za każdym razem po pierwszym nie będzie wykonywana. Wiem Z C++ i Javy o zmiennych statycznych, które mogą wykonać pracę, ale chciałbym wiedzieć, czy jest bardziej elegancki sposób, aby to zrobić?

Author: vlio20, 2012-10-03

21 answers

Jeśli przez "nie zostanie wykonane" masz na myśli "nie zrobi nic, gdy zostanie wywołane więcej niż raz", możesz utworzyć zamknięcie:

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

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

W odpowiedzi na komentarz @Vladloffe (teraz usunięty): w przypadku zmiennej globalnej inny kod może zresetować wartość flagi "executed" (niezależnie od wybranej nazwy). Z zamknięciem inny kod nie może tego zrobić, przypadkowo lub celowo.

Jak wskazują inne odpowiedzi, kilka bibliotek (np. i Ramda ) mają małą funkcję użytkową (Zwykle o nazwie once()[*]) która przyjmuje funkcję jako argument i zwraca inną funkcję, która wywołuje dostarczoną funkcję dokładnie raz, niezależnie od tego, ile razy zwracana funkcja została wywołana. Zwracana funkcja również buforuje wartość najpierw zwróconą przez dostarczoną funkcję i zwraca ją przy kolejnych wywołaniach.

Jednakże, jeśli nie używasz takiej biblioteki innej firmy, ale nadal chcesz takiej funkcji użytkowej (zamiast rozwiązania nonce, które zaproponowałem powyżej), jest wystarczająco łatwe do wdrożenia. Najładniejsza wersja jaką widziałem to ta dodana przez Davida Walsha :

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

[*]należy jednak pamiętać, że inne biblioteki, takie jak to rozszerzenie Drupala do jQuery , mogą mieć funkcję o nazwie once(), która robi coś zupełnie innego.

 157
Author: Ted Hopp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-04 16:16:01

Zastąp go funkcją noop (no operation).

// 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
}
 53
Author: I Hate Lazy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-11 11:44:53

UnderscoreJs ma funkcję, która to robi, 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;
    };
  };
 25
Author: asawyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-03 17:20:18

Po wywołaniu wystarczy wskazać pustą funkcję.

var myFunc = function(){
     myFunc = function(){}; // kill it as soon as it was called
     console.log('call once and never again!'); // your stuff here
};
 19
Author: vsync,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-14 08:35:37

Mówiąc o zmiennych statycznych, jest to trochę jak wariant zamknięcia:

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

once(); once(); 

Możesz następnie zresetować funkcję, jeśli chcesz:

once.done = false;
 6
Author: Bunyk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-14 10:12:06
var quit = false;

function something() {
    if(quit) {
       return;
    } 
    quit = true;
    ... other code....
}
 4
Author: Diodeus - James MacFarlane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-03 17:19:27

Możesz po prostu mieć funkcję "Usuń się"

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

    Once = undefined;
}

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

Ale to może nie być najlepsza odpowiedź, jeśli nie chcesz połykać błędów.

Możesz też to zrobić:
function Once(){
    console.log("run");

    Once = function(){};
}

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

potrzebuję go, aby działał jak inteligentny wskaźnik, jeśli nie ma elementów z Typu A, można go wykonać, jeśli jest jeden lub więcej elementów A, funkcja nie może być wykonana.

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

    // do stuff
}
 4
Author: Shmiddty,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-03 19:19:20

Spróbuj tego

var fun = (function() {
  var called = false;
  return function() {
    if (!called) {
      console.log("I  called");
      called = true;
    }
  }
})()
 2
Author: Database_Query,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-03 17:22:58

Od jakiegoś kolesia o imieniu Crockford... :)

function once(func) {
    return function () {
        var f = func;
        func = null;
        return f.apply(
            this,
            arguments
        );
    };
}
 2
Author: Jowen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-16 10:26:48

Oto przykład JSFiddle- http://jsfiddle.net/6yL6t/

I Kod:

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

Możesz zrobić:

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

I będzie działać tylko raz:)

 1
Author: Aldekein,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-02 14:54:47

Konfiguracja początkowa:

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
Author: andlrc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-28 08:55:47

If your using Node.js lub pisanie JavaScript za pomocą browserify, rozważ " once " moduł npm :

var once = require('once')

function load (file, cb) {
  cb = once(cb)
  loader.load('file')
  loader.once('load', cb)
  loader.once('error', cb)
}
 1
Author: orcaman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-09 12:02:17

Funkcja wielokrotnego użytku invalidate, która działa z 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);

Spróbuj na JSBin: https://jsbin.com/vicipar/edit?js, console

Odpowiedź od Bunyk

 1
Author: user300375,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-27 23:50:45

Jeśli chcesz być w stanie ponownie użyć funkcji w przyszłości, to działa dobrze w oparciu o kod Ed Hopp powyżej (zdaję sobie sprawę, że oryginalne pytanie nie wywołało tej dodatkowej funkcji!):

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

Wyjście wygląda następująco:

Hello World!
Reset
Hello World!
 1
Author: CMP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-21 01:47:59

Próba użycia funkcji podkreślenia "raz":

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

Http://underscorejs.org/#once

 0
Author: Andrew Feng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-17 11:15:34
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
Author: developer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-13 17:58:03

Jeśli używasz Ramda, możesz użyć funkcji "once" .

Cytat z dokumentacji:

Once Function (a ... → b) → (a ... → b) Parametry Dodano w v0. 1. 0

Akceptuje funkcję fn i zwraca funkcję, która strzeże wywołania fn tak, że fn może być wywołana tylko raz, bez względu na to, ile razy zwracana funkcja została wywołana. Pierwsza obliczona wartość jest zwracana w kolejnych wywołaniach.

var addOneOnce = R.once(x => x + 1);
addOneOnce(10); //=> 11
addOneOnce(addOneOnce(50)); //=> 11
 0
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-25 16:01:32

Przychodzę z prostym dekoratorem, który łatwo rozwiązuje twój problem]}

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

Użycie:

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

initializer() // 'initializing'
initializer() // nop
initializer() // nop
 0
Author: pery mimon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-14 08:12:49
if (!window.doesThisOnce){
  function myFunction() {
    // do something
    window.doesThisOnce = true;
  };
};
 -1
Author: Adrian Mann,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-12 19:13:58

Ten jest przydatny do zapobiegania nieskończonym pętlom (używając jQuery):

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

Jeśli martwisz się zanieczyszczeniem przestrzeni nazw, zastąp długi, losowy łańcuch dla "doIt".

 -2
Author: Elliot Gorokhovsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-01 23:51:56

Pomaga zapobiegać lepkiemu wykonaniu

var done = false;

function doItOnce(func){
  if(!done){
    done = true;
    func()
  }
  setTimeout(function(){
    done = false;
  },1000)
}
 -2
Author: Gleb Dolzikov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-05-11 08:45:37