【问题标题】:Init function in javascript and how it worksjavascript中的init函数及其工作原理
【发布时间】:2010-11-18 06:17:24
【问题描述】:

我经常看到如下代码:

(function () {
  // init part
})();

但我始终无法理解它是如何工作的。我发现最后一个括号特别令人困惑。 有人可以根据执行上下文 (EC) 和变量对象 (VO) 来解释它是如何工作的吗?

【问题讨论】:

标签: javascript


【解决方案1】:

我通常向人们解释这一点的方式是展示它与其他 JavaScript 模式的相似之处。

首先,你应该知道有两种方式来声明一个函数(实际上,至少有五种,但这是两个主要的罪魁祸首):

function foo() {/*code*/}

var foo = function() {/*code*/};

即使这个结构看起来很奇怪,你可能在附加事件时一直使用它:

window.onload=function(){/*code*/};

您应该注意到第二种形式与常规变量声明没有太大区别:

var bar = 5;
var baz = 'some string';
var foo = function() {/*code*/};

但在 JavaScript 中,您总是可以选择直接使用值还是通过变量。如果bar5,那么接下来的两个语句是等价的:

var myVal = bar * 100; // use 'bar'
var myVal = 5 * 100;   // don't use 'bar'

好吧,如果你可以单独使用5,为什么你不能单独使用function() {\*code*\}?事实上,你可以。这就是所谓的匿名函数。所以这两个例子也是等价的:

var foo = function() {/*code*/}; // use 'foo'
foo();                           

(function(){/*code*/})();        // don't use 'foo' 

您应该看到的唯一区别是额外的括号。这仅仅是因为如果您以关键字 function 开始一行,解析器会认为您正在使用此答案顶部的第一个模式声明一个函数并引发语法错误异常。因此,将您的整个匿名函数包裹在一对大括号中,问题就消失了。

也就是说,以下三种说法是有效的:

5;                        // pointless and stupid
'some string';            // pointless and stupid
(function(){/*code*/})(); // wonderfully powerful

[2020 年编辑]

我的回答的先前版本推荐了 Douglas Crockford 的括号包装形式,用于这些“立即调用的匿名函数”。用户 @RayLoveless 在 2012 年推荐使用现在显示的版本。那时候,在 ES6 和箭头函数之前,并没有明显的惯用差异;您只需阻止以 function 关键字开头的语句。事实上,有很多方法可以做到这一点。但是使用括号,这两个语句在语法和习惯上是等效的:

( function() { /* code */}() );
( function() { /* code */} )();

但用户@zentechinc 下面的评论提醒我箭头功能改变了这一切。所以现在只有这些陈述中的一个是正确的。

( () => { /* code */ }() ); // Syntax error
( () => { /* code */ } )();

这到底为什么重要?实际上,它很容易演示。请记住,箭头函数可以有两种基本形式:

() => { return 5; };       // With a function body
() => { console.log(5); };

() => 5;                   // Or with a single expression
() => console.log(5);

如果没有包裹第二种类型的箭头函数的括号,你最终会得到一个惯用的混乱:

() => 5();              // How do you invoke a 5?
() => console.log(5)(); // console.log does not return a function!

【讨论】:

  • “我通常向人们解释这一点的方式是展示它与其他 JavaScript 模式的相似之处。”这非常有帮助,所以感谢您抽出宝贵的时间这样做:)
  • 我想你输入了 (function(){/*code*/}());你的意思是输入 (function(){/*code*/})();。对吗?
  • 不,但没关系。道格拉斯·克罗克福德(Douglas Crockford)推荐我使用的表格,而很多人推荐您的表格。见stackoverflow.com/questions/3783007/…。碰巧,使用括号的原因是您试图避免以function 开始声明(因此您可以轻松地使用!function(){/*code*/}()-function(){/*code*/}()。我不喜欢Crockford 推荐的所有内容,但我认为他严格的一致性优于每个人随心所欲的替代方案,他的 linting 工具 (JSLint) 需要它。
  • @RayLoveless 这似乎不是胖箭头函数的情况 (() => {console.log('我在这里!')}()) 无法运行 while (function () {console.log(' HERE I AM! ')})() 工作得很好,它是一个非常古老的评论,但仍然很有趣最重要的是这些变化。谢谢你的回答,顺便说一句。
  • @zentechinc,实际上,这是一个很好的观点,它表明我对括号放置的评论是惯用的不正确的。这在 2010 年并不明显。我会更新我的答案。
【解决方案2】:

该模式将创建一个新的执行上下文 (EC),任何局部变量对象 (VO) 都将在其中生存,并且在 EC 退出时同样会死亡。此生命周期的唯一例外是成为 closure 一部分的 VO。

请注意,JavaScript 没有神奇的“init”函数。您可能会将这种模式与这种模式联系起来,因为大多数自尊的 JS 库(jQuery、YUI 等)都会这样做,这样它们就不会过多地污染全局 NS。

演示:

var x = 1; // global VO
(function(){        
    var x = 2; // local VO
})();
x == 1; // global VO, unchanged by the local VO

第二组“括号”(实际上称为括号或一组括号)只是调用其前面的函数表达式(由前面的括号组定义)。

【讨论】:

  • 现在,如果您向不理解的开发人员解释 EC 和 VO 是什么,那么我会给您一个赞成票,但不是完整的答案,我可能不得不谷歌的首字母缩略词。
  • 我没有定义 EC 和 VO,因为原始问题包含这些定义,所以如果您阅读了问题,那么您应该已经知道它们的含义;)另外,这两页可能会帮助您理解EC/VO(变量)更好:1.jibbering.com/faq 2.jibbering.com/faq/notes/closures
【解决方案3】:

代码创建一个匿名函数,然后立即运行它。类似于:

var temp = function() {
  // init part
}
temp();

这种构造的目的是为函数内部的代码创建一个作用域。您可以在范围内声明变量和函数,这些变量和函数将在该范围内。这样它们就不会弄乱全局范围,从而最大限度地降低与其他脚本发生冲突的风险。

【讨论】:

  • 尊敬的,对于那些一直支持这个答案的人,给定的解决方案没有回答 OP 提出的任何问题根本。他询问最后一组括号 [原文如此] 以及给定代码与 EC 和 VO 的关系... Guffa 提供的内容看起来像是普通的匿名函数答案,没有解决具体问题OP提出来了。
  • @ken:人们似乎喜欢我解释代码的作用以及使用它的原因。仅仅因为我没有使用您使用的确切术语,这并没有错。
  • 我从未说过这是/错误/,我只是指出您的复制/粘贴答案没有考虑到 OP 的要求,仅此而已。
  • 愚蠢的问题,但“初始化部分”是什么意思? “初始化”这个词让我很困惑
  • @PulledBull:Init 代表初始化/初始化。在这种情况下,它只是意味着代码在页面被解析时运行。首先发生这种情况,这是初始化事物的好地方。
【解决方案4】:

我不敢相信没有人回答过运维问题!

最后一组括号用于将参数传递给匿名函数。因此,以下示例创建了一个函数,然后使用 x=5 和 y=8 运行它

(function(x,y){
    //code here
})(5,8)

这可能看起来没那么有用,但它有它的位置。我见过的最常见的是

(function($){
    //code here
})(jQuery)

它允许 jQuery 处于兼容模式,但您可以在匿名函数中将其称为“$”。

【讨论】:

  • 这也可以通过缩短特定变量的scope chain 来提高性能。
【解决方案5】:

自调用匿名函数 (SIAF)

即使 DOM 尚未完全准备好,自调用函数也会立即运行。

jQuery document.ready vs self calling anonymous function

【讨论】:

  • 感谢您与此线程分享名称...非常有帮助
【解决方案6】:

简单来说,你可以理解,每当页面加载时,通过这第二对括号()函数就会调用default。我们不需要调用这个函数。它被称为匿名函数。

(function(a,b){
//Do your code here
})(1,2);

一样
var test = function(x,y) {
  // Do your code here
}
test(1,2);

【讨论】:

    【解决方案7】:

    它被称为立即调用函数表达式(IIFE)。主要与 JavaScript 闭包概念有关。主要用途是在全局变量改变之前运行函数,这样可以保留代码的预期行为。

    猜你喜欢
    • 2011-10-07
    • 1970-01-01
    • 1970-01-01
    • 2021-07-07
    • 2012-02-28
    • 2012-03-23
    • 2013-04-22
    • 1970-01-01
    相关资源
    最近更新 更多