JavaScript - 没有布尔值运行一次

时间:2010-09-09 16:40:49

标签: optimization javascript

有没有办法只运行一段JavaScript代码 ONCE ,而不使用布尔标志变量来记住它是否已经运行过?

特别是之类的内容:

var alreadyRan = false;
function runOnce() {
  if (alreadyRan) {
    return;
  }
  alreadyRan = true;

  /* do stuff here */

}

我将会有很多这些类型的功能,并且保持所有布尔值都会变得凌乱......

9 个答案:

答案 0 :(得分:75)

执行时覆盖函数的另一种方法,它只执行一次。

function useThisFunctionOnce(){
   // overwrite this function, so it will be executed only once
   useThisFunctionOnce = Function("");
   // real code below
   alert("Hi!");
}

// displays "Hi!"
useThisFunctionOnce();
// does nothing
useThisFunctionOnce();

'有用'示例:

var preferences = {};
function read_preferences(){
   // read preferences once
   read_preferences = Function("");
   // load preferences from storage and save it in 'preferences'
}
function readPreference(pref_name){
    read_prefences();
    return preferences.hasOwnProperty(pref_name) ? preferences[pref_name] : '';
}
if(readPreference('like_javascript') != 'yes'){
   alert("What's wrong wth you?!");
}
alert(readPreference('is_stupid') ? "Stupid!" : ":)");

编辑:正如CMS指出的那样,只需用function(){}覆盖旧函数将创建一个旧变量仍然存在的闭包。要解决该问题,function(){}将替换为Function("")。这将在全局范围内创建一个空函数,从而避免关闭。

答案 1 :(得分:9)

我喜欢Lekensteyn的实现,但你也可以只有一个变量来存储运行的函数。下面的代码应该一次运行“runOnce”和“runAgain”。它仍然是布尔值,但听起来你只是不想要很多变量。

var runFunctions = {};

function runOnce() {
  if(!hasRun(arguments.callee)) {
   /* do stuff here */
   console.log("once");
  }
}

function runAgain() {
  if(!hasRun(arguments.callee)) {
   /* do stuff here */
   console.log("again");
  }
}


function hasRun(functionName) {
 functionName = functionName.toString();
 functionName = functionName.substr('function '.length);
 functionName = functionName.substr(0, functionName.indexOf('('));

 if(runFunctions[functionName]) {
   return true;
 } else {
   runFunctions[functionName] = true;
   return false;
 }
}

runOnce();
runAgain();
runAgain();

答案 2 :(得分:8)

这些方法中的一个问题是它们依赖于函数名称来工作:如果使用“x = function()...”创建函数,Mike的方法将失败,如果设置了Lekensteyn的方法将失败x = useThisFunctionOnce在useThisFunctionOnce被调用之前。

如果您希望立即运行,或者如果您想延迟执行Underscore.js采取的方法,我建议使用Russ的闭包方法:

function once(func) {
    var ran = false, memo;
    return function() {
        if (ran) return memo;
        ran = true;
        return memo = func.apply(this, arguments);
    };
}

var myFunction = once(function() {
    return new Date().toString();
});

setInterval(function() {console.log(myFunction());}, 1000);

在第一次执行时,执行内部函数并返回结果。在后续运行中,将返回原始结果对象。

答案 3 :(得分:6)

如何立即调用匿名函数?

(function () {

    // code in here to run once

})();

代码将立即执行,并且不会在全局命名空间中留下任何痕迹。

如果需要从其他地方调用此代码,则可以使用闭包来确保函数的内容只运行一次。就个人而言,我更喜欢这个函数重写自己,因为我觉得这样做会引起混淆,但是每个人都有自己的:)这个特殊的实现利用了0是一个假值的事实。

var once = (function() {
  var hasRun = 0;  
  return function () {
    if (!hasRun) {
      hasRun++;   

      // body to run only once

      // log to the console for a test       
      console.log("only ran once");
    }              
  }
})();

// test that the body of the function executes only once
for (var i = 0; i < 5; i++) 
  once();

答案 4 :(得分:3)

来自Douglas Crockford的优雅解决方案花了一些时间来了解它是如何工作的,并偶然发现了这个主题。

所以包装器一旦返回函数,它只调用你传递的参数函数。并且利用闭包这个构造在第一次调用之后将传递的函数替换为空函数,或者在原始源中将null替换为null,因此所有下一个调用都将是无用的。

这是非常接近所有其他答案的东西,但它有点自包含代码,你可以独立使用它,这很好。我仍然试图掌握所有替换的整个机制,但实际上它只是完美无缺。

function once (func) {

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

}

function hi(name) {
  console.log("Hi %s", name);
}

sayonce = once(hi);
sayonce("Vasya");
sayonce("Petya");

对于那些好奇的人来说是jsbin转换

答案 5 :(得分:1)

(function (){

  var run = (function (){

    var func, blank = function () {};

    func = function () {
      func = blank;

      // following code executes only once 
      console.log('run once !');
    };

    return function(){
      func.call();
    };
  })();

  run();
  run();
  run();
  run();

})();

答案 6 :(得分:1)

我刚遇到这个问题,最后做了类似以下的事情:

function runOnce () {
    if (!this.alreadyRan) {
        // put all your functionality here
        console.log('running my function!');

        // set a property on the function itself to prevent it being run again
        this.alreadyRan = true;
    }
}

这利用了默认情况下未定义Javascript属性的事实。

答案 7 :(得分:0)

此外,“/ * do stuff here / /”中发生的事情的性质可能会留下一些东西,如果存在,必须意味着函数已经运行,例如。

var counter = null;

function initCounter() {
  if (counter === null) {
    counter = 0;
  }
}

答案 8 :(得分:-2)

如果没有绑定到某个事件,代码通常会运行一次