JavaScript - 没有布尔值运行一次

tes*_*est 30 javascript optimization

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

特别是不是这样的:

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

  /* do stuff here */

}
Run Code Online (Sandbox Code Playgroud)

我将有很多这些类型的功能,并保持所有布尔将是凌乱的......

Lek*_*eyn 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();
Run Code Online (Sandbox Code Playgroud)

'有用'的例子:

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!" : ":)");
Run Code Online (Sandbox Code Playgroud)

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

  • 我强烈反对*使用这种模式,因为*所有*变量,参数和第一个函数的内部FunctionDeclarations将永远不会被垃圾收集,这可能不是很明显,但它是真的,在第一个函数中创建了空函数,这将创建一个闭包,并且所有标识符将保持*live*,从而产生内存泄漏.我建议使用外部声明空函数,或使用函数构造函数,例如`useThisFunctionOnce = Function("");`.尝试[this test](http://j.mp/aVlAiX)查看所有变量保持在范围内的效率. (17认同)
  • 确实+1!赋予"此功能在首次使用后会自毁"的新含义. (6认同)

Mik*_*son 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();
Run Code Online (Sandbox Code Playgroud)


Bri*_*kel 8

很多这些方法的问题在于它们依赖于函数名称来工作:如果使用"x = function()..."创建函数,Mike的方法将失败,如果设置x = useThisFunctionOnce,则Lekensteyn的方法将失败在使用之前调用ThisFunctionOnce.

如果你想运行它马上或所采取的方法,我会建议使用拉斯的关闭方法Underscore.js如果要延迟执行:

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);
Run Code Online (Sandbox Code Playgroud)

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


Rus*_*Cam 6

如何立即调用匿名函数?

(function () {

    // code in here to run once

})();
Run Code Online (Sandbox Code Playgroud)

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

如果需要从其他地方调用此代码,则可以使用闭包来确保函数的内容只运行一次.就个人而言,我更喜欢这个函数重写自己,因为我觉得这样做会引起混淆,但是每个人都有自己的:)这个特殊的实现利用了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();
Run Code Online (Sandbox Code Playgroud)