Javascript:内联函数与预定义函数

gla*_*666 44 javascript coding-style

任何正文都可以抛出一些参数来使用内联函数来防止将预定义函数名称传递给某个处理程序.

即哪个更好:

(function() {
  setTimeout(function() { /*some code here*/ }, 5);
})();
Run Code Online (Sandbox Code Playgroud)

(function() {
  function invokeMe() {
    /*code*/
  }
  setTimeout(invokeMe, 5);
})();
Run Code Online (Sandbox Code Playgroud)

奇怪的问题,但我们几乎在团队中争论这件事

Pre*_*aul 52

命名功能

本页的问答中有一些严重滥用术语的行为.没有关于函数是否为内联函数(函数表达式)的信息,表明您无法命名它.

这是使用函数表达式:

setTimeout(function doSomethingLater() { alert('In a named function.'); }, 5);
Run Code Online (Sandbox Code Playgroud)

这是使用函数语句:

function doSomethingLater() { alert('In a named function.'); }
setTimeout(doSomethingLater, 5);
Run Code Online (Sandbox Code Playgroud)

这两个示例都使用了命名函数,并且在调试和分析工具方面都获得了相同的好处!

如果指定了名称("函数"之后但在括号之前的文本),那么它是一个命名函数,无论它是内联还是单独声明.如果未指定名称,则为"匿名".

注意:TJ指出IE错误地处理命名的函数表达式(请参阅:http://kangax.github.com/nfe/#jscript-bugs),这一点很重要,我只是想尝试指出术语.

你应该用哪个?

在回答您的直接问题时,如果可以从代码中的任何其他位置使用该函数,则应使用命名函数语句.如果函数只在一个地方使用并且在其他地方没有相关性,那么我会使用一个函数表达式,除非它过长或者感觉不合适(出于样式原因).如果使用内联函数表达式,那么为了调试或代码清晰度的目的,无论如何命名它通常很有用.

内存泄漏

无论是命名函数,使用函数语句还是使用函数表达式都对内存泄漏问题影响不大.让我试着解释导致这些泄漏的原因.看看这段代码:

(function outerFunction() {
    var A = 'some variable';

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

在上面的代码中,当"outerFunction"完成"A"超出范围并且可以被垃圾收集时,释放该内存.

如果我们在那里添加一个函数怎么办?

(function outerFunction() {
    var A = 'some variable';

   setTimeout(function(){ alert('I have access to A whether I use it or not'); }, 5);
})();
Run Code Online (Sandbox Code Playgroud)

在此代码(以上)我们传递到setTimeout的函数表达式为"A"(通过闭合的魔术),甚至后"outerFunction"结束的基准"A"将保持在存储器中,直到超时被触发,并且功能被解除引用.

如果我们将该函数传递给setTimeout以外的其他函数怎么办?

(function outerFunction() {
    var A = 'some variable';

   doStuff(function(){ alert('I have access to A whether I use it or not'); });
})();

function doStuff(fn) {
    someElement.onclick = fn;
}
Run Code Online (Sandbox Code Playgroud)

现在,我们正在传递到"doStuff"函数表达式即使"outerFunction"结束获得"A"和"A"将保留在内存中,只要有我们所传递到doStuff函数的引用.在这种情况下,我们正在创建对该函数的引用(作为事件处理程序),因此"A"将保留在内存中,直到该事件处理程序被清除.(例如有人打电话someElement.onclick = null)

现在看看当我们使用函数语句时会发生什么:

(function outerFunction() {
    var A = 'some variable';

    function myFunction() { alert('I have also have access to A'); };
    doStuff(myFunction);
})();
Run Code Online (Sandbox Code Playgroud)

一样的问题!只有当"doStuff"没有对其进行引用时才会清除"myFunction",并且只有在清除"myFunction"时才会清除"A".无论我们使用的是陈述还是表达,都无关紧要; 重要的是,如果在"doStuff"中创建了对该函数的引用!

  • @ th1rdey3,一旦你知道如何在javascript中管理作用域,就会更容易避免.关键是:**保持函数较小并以尽可能低的可见性创建变量.**这意味着:不创建全局变量,函数应该只做一件事,如果变量只需要函数内部,var它在那个功能里面.而已. (2认同)

T.J*_*der 11

两者之间存在一个显着差异:后者有一个名称.

我喜欢帮助我的工具帮助我,因此我主要避免使用匿名函数,因为我的工具无法向我提供有关它们的有意义的信息(例如,在调试器中的调用堆栈列表中等).所以我会选择

(function(){
  function invokeMe() {
    /*code*/
  }
  setTimeout(invokeMe, 5);
})();
Run Code Online (Sandbox Code Playgroud)

......形式一般.但是,规则应该被打破,而不是盲目地屈服于.:-)

请注意,根据规范,还有第三种选择:您可以使用也具有名称的内联函数:

(function(){
  setTimeout(function invokeMe(){ /*some code here*/ }, 5);
})();
Run Code Online (Sandbox Code Playgroud)

但问题是,到目前为止,Microsoft的JavaScript解释器("JScript")的每个版本,包括(惊人地)IE9中的那个,都会错误地处理该命名函数表达式,并在不同时间创建两个完全不同的函数.(证明,在IE9或更早版本以及几乎任何其他浏览器中尝试它.)IE在两个方面弄错了:1.它创建了两个独立的函数对象,并且2.由于其中一个,它"流血" "将名称符号放入表达式的封闭范围内(明显违反规范第13节).详细信息:双重拍摄


CMS*_*CMS 5

IMO,声明一个函数只有在你打算以其他方式重新使用它时才有用.

我个人使用函数表达式(第一种方式)setTimeout处理程序.

但是您可能想知道函数声明和函数表达式之间的区别,我建议您阅读以下文章: