将整个 Javascript 文件包装在像“(function(){ … })()”这样的匿名函数中的目的是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2421911/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the purpose of wrapping whole Javascript files in anonymous functions like “(function(){ … })()”?
提问by Andrew Kou
I have been reading a lot of Javascript lately and I have been noticing that the whole file is wrapped like the following in the .js files to be imported.
我最近阅读了很多 Javascript,我注意到整个文件在要导入的 .js 文件中如下所示。
(function() {
...
code
...
})();
What is the reason for doing this rather than a simple set of constructor functions?
这样做而不是一组简单的构造函数的原因是什么?
回答by Vivin Paliath
It's usually to namespace (see later) and control the visibility of member functions and/or variables. Think of it like an object definition. The technical name for it is an Immediately Invoked Function Expression(IIFE). jQuery plugins are usually written like this.
通常是命名空间(见下文)并控制成员函数和/或变量的可见性。把它想象成一个对象定义。它的技术名称是立即调用函数表达式(IIFE)。jQuery 插件通常是这样编写的。
In Javascript, you can nest functions. So, the following is legal:
在 Javascript 中,您可以嵌套函数。所以,以下是合法的:
function outerFunction() {
function innerFunction() {
// code
}
}
Now you can call outerFunction(), but the visiblity of innerFunction()is limited to the scope of outerFunction(), meaning it is private to outerFunction(). It basically follows the same principle as variables in Javascript:
现在您可以调用outerFunction(),但是 的可见性innerFunction()仅限于 的范围outerFunction(),这意味着它是私有的outerFunction()。它基本上遵循与 Javascript 中的变量相同的原则:
var globalVariable;
function someFunction() {
var localVariable;
}
Correspondingly:
相应地:
function globalFunction() {
var localFunction1 = function() {
//I'm anonymous! But localFunction1 is a reference to me!
};
function localFunction2() {
//I'm named!
}
}
In the above scenario, you can call globalFunction()from anywhere, but you cannot call localFunction1or localFunction2.
在上述场景中,您可以globalFunction()从任何地方调用,但不能调用localFunction1或localFunction2。
What you're doing when you write (function() { ... })(), is you're making the code inside the first set of parentheses a function literal (meaning the whole "object" is actually a function). After that, you're self-invoking the function (the final ()) that you just defined. So the major advantage of this as I mentioned before, is that you can have private methods/functions and properties:
您在编写时所做的(function() { ... })()是将第一组括号内的代码作为函数文字(意味着整个“对象”实际上是一个函数)。之后,您将自调用()刚刚定义的函数(最后一个)。因此,正如我之前提到的,这样做的主要优点是您可以拥有私有方法/函数和属性:
(function() {
var private_var;
function private_function() {
//code
}
})();
In the first example, you would explicitly invoke globalFunctionby name to run it. That is, you would just do globalFunction()to run it. But in the above example, you're not just defining a function; you're defining andinvoking it in one go. This means that when the your JavaScript file is loaded, it is immediately executed. Of course, you could do:
在第一个示例中,您将按globalFunction名称显式调用以运行它。也就是说,您只需globalFunction()运行它即可。但在上面的例子中,你不仅仅是在定义一个函数;您可以一次性定义和调用它。这意味着当您的 JavaScript 文件加载时,它会立即执行。当然,你可以这样做:
function globalFunction() {
// code
}
globalFunction();
The behavior would largely be the same except for one significant difference: you avoid polluting the global scope when you use an IIFE (as a consequence it also means that you cannot invoke the function multiple times since it doesn't have a name, but since this function is only meant to be executed once it really isn't an issue).
除了一个显着差异外,行为基本相同:使用 IIFE 时避免污染全局范围(因此,这也意味着您不能多次调用该函数,因为它没有名称,但是由于此函数仅意味着在它确实不是问题时才执行)。
The neat thing with IIFEs is that you can also define things inside and only expose the parts that you want to the outside world so (an example of namespacing so you can basically create your own library/plugin):
IIFE 的巧妙之处在于您还可以在内部定义事物,并且只将您想要的部分暴露给外部世界(命名空间示例,因此您基本上可以创建自己的库/插件):
var myPlugin = (function() {
var private_var;
function private_function() {
}
return {
public_function1: function() {
},
public_function2: function() {
}
}
})()
Now you can call myPlugin.public_function1(), but you cannot access private_function()! So pretty similar to a class definition. To understand this better, I recommend the following links for some further reading:
现在你可以打电话myPlugin.public_function1(),但你不能访问private_function()!非常类似于类定义。为了更好地理解这一点,我推荐以下链接以供进一步阅读:
EDIT
编辑
I forgot to mention. In that final (), you can pass anything you want inside. For example, when you create jQuery plugins, you pass in jQueryor $like so:
我忘了提。在那个 final 中(),你可以传递任何你想要的东西。例如,当你创建 jQuery 插件时,你传入jQuery或$像这样:
(function(jQ) { ... code ... })(jQuery)
So what you're doing here is defining a function that takes in one parameter (called jQ, a local variable, and known onlyto that function). Then you're self-invoking the function and passing in a parameter (also called jQuery, but thisone is from the outside world and a reference to the actual jQuery itself). There is no pressing need to do this, but there are some advantages:
所以你在这里所做的是定义一个函数,它接受一个参数(称为jQ,一个局部变量,并且只为该函数所知)。然后,您将自调用该函数并传入一个参数(也称为jQuery,但该参数来自外部世界并且是对实际 jQuery 本身的引用)。没有迫切需要这样做,但有一些优点:
- You can redefine a global parameter and give it a name that makes sense in the local scope.
- There is a slight performance advantage since it is faster to look things up in the local scope instead of having to walk up the scope chain into the global scope.
- There are benefits for compression (minification).
- 您可以重新定义全局参数并为其指定一个在本地范围内有意义的名称。
- 有一个轻微的性能优势,因为在本地范围内查找内容更快,而不必沿着作用域链向上遍历到全局作用域。
- 压缩(缩小)有好处。
Earlier I described how these functions run automatically at startup, but if they run automatically who is passing in the arguments? This technique assumes that all the parameters you need are already defined as global variables. So if jQuery wasn't already defined as a global variable this example would not work. As you might guess, one things jquery.js does during its initialization is define a 'jQuery' global variable, as well as its more famous '$' global variable, which allows this code to work after jQuery has been included.
前面我描述了这些函数如何在启动时自动运行,但如果它们自动运行,谁在传递参数?此技术假定您需要的所有参数都已定义为全局变量。因此,如果 jQuery 尚未定义为全局变量,则此示例将不起作用。正如您可能猜到的,jquery.js 在初始化期间所做的一件事是定义一个“jQuery”全局变量,以及它更著名的“$”全局变量,它允许在包含 jQuery 后运行此代码。
回答by Adrien Be
In short
简而言之
Summary
概括
In its simplest form, this technique aims to wrap code inside a function scope.
以最简单的形式,此技术旨在将代码包装在函数作用域内。
It helps decreases chances of:
它有助于减少以下机会:
- clashing with other applications/libraries
- polluting superior (global most likely) scope
- 与其他应用程序/库冲突
- 污染上级(全球最有可能)范围
It does notdetect when the document is ready - it is not some kind of document.onloadnor window.onload
它不会检测文档何时准备就绪 - 它不是某种document.onload或window.onload
It is commonly known as an Immediately Invoked Function Expression (IIFE)or Self Executing Anonymous Function.
它通常被称为Immediately Invoked Function Expression (IIFE)或Self Executing Anonymous Function。
Code Explained
代码解释
var someFunction = function(){ console.log('wagwan!'); };
(function() { /* function scope starts here */
console.log('start of IIFE');
var myNumber = 4; /* number variable declaration */
var myFunction = function(){ /* function variable declaration */
console.log('formidable!');
};
var myObject = { /* object variable declaration */
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
})(); /* function scope ends */
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
In the example above, any variable defined in the function (i.e. declared using var) will be "private" and accessible within the function scope ONLY (as Vivin Paliath puts it). In other words, these variables are not visible/reachable outside the function. See live demo.
在上面的例子中,函数中定义的任何变量(即使用声明var)将是“私有的”,并且只能在函数范围内访问(正如 Vivin Paliath 所说)。换句话说,这些变量在函数外部不可见/不可访问。见现场演示。
Javascript has function scoping. "Parameters and variables defined in a function are not visible outside of the function, and that a variable defined anywhere within a function is visible everywhere within the function." (from "Javascript: The Good Parts").
Javascript 具有函数作用域。“在函数中定义的参数和变量在函数外是不可见的,在函数内任何地方定义的变量在函数内的任何地方都是可见的。” (来自“Javascript:好的部分”)。
More details
更多细节
Alternative Code
替代代码
In the end, the code posted before could also be done as follows:
最后,之前贴出的代码也可以这样:
var someFunction = function(){ console.log('wagwan!'); };
var myMainFunction = function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
};
myMainFunction(); // I CALL "myMainFunction" FUNCTION HERE
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
The Roots
根
Iteration 1
迭代 1
One day, someone probably thought "there must be a way to avoid naming 'myMainFunction', since all we want is to execute it immediately."
有一天,有人可能认为“一定有一种方法可以避免命名 'myMainFunction',因为我们想要的只是立即执行它。”
If you go back to the basics, you find out that:
如果你回到基础,你会发现:
expression: something evaluating to a value. i.e.3+11/xstatement: line(s) of code doing something BUT it does notevaluate to a value. i.e.if(){}
expression: 评估值的东西。IE3+11/xstatement:线(S)的代码做的东西,但它并没有计算到的值。IEif(){}
Similarly, function expressions evaluate to a value. And one consequence (I assume?) is that they can be immediately invoked:
类似地,函数表达式的计算结果为一个值。一个结果(我假设?)是它们可以立即被调用:
var italianSayinSomething = function(){ console.log('mamamia!'); }();
So our more complex example becomes:
所以我们更复杂的例子变成了:
var someFunction = function(){ console.log('wagwan!'); };
var myMainFunction = function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
}();
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
Iteration 2
迭代 2
The next step is the thought "why have var myMainFunction =if we don't even use it!?".
下一步是“var myMainFunction =如果我们甚至不使用它为什么要使用它!?”。
The answer is simple: try removing this, such as below:
答案很简单:尝试删除它,如下所示:
function(){ console.log('mamamia!'); }();
It won't work because "function declarations are not invokable".
它不起作用,因为“函数声明不可调用”。
The trick is that by removing var myMainFunction =we transformed the function expressioninto a function declaration. See the links in "Resources" for more details on this.
诀窍是通过删除var myMainFunction =我们将函数表达式转换为函数声明。有关这方面的更多详细信息,请参阅“资源”中的链接。
The next question is "why can't I keep it as a function expression with something other than var myMainFunction =?
下一个问题是“为什么我不能将其保留为带有除 之外的其他内容的函数表达式var myMainFunction =?
The answer is "you can", and there are actually many ways you could do this: adding a +, a !, a -, or maybe wrapping in a pair of parenthesis (as it's now done by convention), and more I believe. As example:
答案是“你可以”,实际上有很多方法可以做到这一点:添加 a +、 a !、 a -,或者用一对括号括起来(就像现在的惯例一样),我相信还有更多。例如:
(function(){ console.log('mamamia!'); })(); // live demo: jsbin.com/zokuwodoco/1/edit?js,console.
or
或者
+function(){ console.log('mamamia!'); }(); // live demo: jsbin.com/wuwipiyazi/1/edit?js,console
or
或者
-function(){ console.log('mamamia!'); }(); // live demo: jsbin.com/wejupaheva/1/edit?js,console
- What does the exclamation mark do before the function?
- JavaScript plus sign in front of function name
So once the relevant modification is added to what was once our "Alternative Code", we return to the exact same code as the one used in the "Code Explained" example
因此,一旦将相关修改添加到曾经是我们的“替代代码”中,我们将返回与“代码解释”示例中使用的完全相同的代码
var someFunction = function(){ console.log('wagwan!'); };
(function() {
console.log('start of IIFE');
var myNumber = 4;
var myFunction = function(){ console.log('formidable!'); };
var myObject = {
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
console.log('end of IIFE');
})();
someFunction(); // reachable, hence works: see in the console
myFunction(); // unreachable, will throw an error, see in the console
myObject.anotherFunc(); // unreachable, will throw an error, see in the console
Read more about Expressions vs Statements:
阅读更多关于Expressions vs Statements:
- developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Function_constructor_vs._function_declaration_vs._function_expression
- Javascript: difference between a statement and an expression?
- Expression Versus Statement
- developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators
- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Function_constructor_vs._function_declaration_vs._function_expression
- Javascript:语句和表达式之间的区别?
- 表达式与语句
Demystifying Scopes
揭秘范围
One thing one might wonder is "what happens when you do NOT define the variable 'properly' inside the function -- i.e. do a simple assignment instead?"
人们可能想知道的一件事是“如果您没有在函数内部‘正确’地定义变量——即进行简单的赋值,会发生什么?”
(function() {
var myNumber = 4; /* number variable declaration */
var myFunction = function(){ /* function variable declaration */
console.log('formidable!');
};
var myObject = { /* object variable declaration */
anotherNumber : 1001,
anotherFunc : function(){ console.log('formidable!'); }
};
myOtherFunction = function(){ /* oops, an assignment instead of a declaration */
console.log('haha. got ya!');
};
})();
myOtherFunction(); // reachable, hence works: see in the console
window.myOtherFunction(); // works in the browser, myOtherFunction is then in the global scope
myFunction(); // unreachable, will throw an error, see in the console
Basically, if a variable that was not declared in its current scope is assigned a value, then "a look up the scope chain occurs until it finds the variable or hits the global scope (at which point it will create it)".
基本上,如果未在其当前作用域中声明的变量被赋值,则“查找作用域链直到它找到该变量或命中全局作用域(此时它将创建它)”。
When in a browser environment (vs a server environment like nodejs) the global scope is defined by the windowobject. Hence we can do window.myOtherFunction().
在浏览器环境中(相对于像 nodejs 这样的服务器环境),全局范围由window对象定义。因此我们可以做到window.myOtherFunction()。
My "Good practices" tip on this topic is to always use varwhen defining anything: whether it's a number, object or function, & even when in the global scope. This makes the code much simpler.
我关于这个主题的“良好实践”提示是在定义任何东西时始终使用var:无论是数字、对象还是函数,甚至在全局范围内。这使得代码更简单。
Note:
笔记:
- javascript does nothave
block scope(Update: block scope local variables added in ES6.) - javascript has only
function scope&global scope(windowscope in a browser environment)
- JavaScript并没有有
block scope(更新:在添加区块范围的局部变量ES6)。 - javascript 只有
function scope&global scope(window在浏览器环境中的范围)
Read more about Javascript Scopes:
阅读更多关于Javascript Scopes:
- What is the purpose of the var keyword and when to use it (or omit it)?
- What is the scope of variables in JavaScript?
Resources
资源
- youtu.be/i_qE1iAmjFg?t=2m15s- Paul Irish presents the IIFE at min 2:15, do watch this!
- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions
- Book: Javascript, the good parts- highly recommended
- youtu.be/i_qE1iAmjFg?t=4m36s- Paul Irish presents the module pattern at 4:36
- youtu.be/i_qE1iAmjFg?t=2m15s- Paul Irish 在 2:15 分展示 IIFE,一定要看!
- developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions
- 书:Javascript,好的部分- 强烈推荐
- youtu.be/i_qE1iAmjFg?t=4m36s- Paul Irish 在 4:36 展示了模块模式
Next Steps
下一步
Once you get this IIFEconcept, it leads to the module pattern, which is commonly done by leveraging this IIFE pattern. Have fun :)
一旦你有了这个IIFE概念,它就会导致module pattern,这通常是通过利用这种 IIFE 模式来完成的。玩得开心 :)
回答by Gareth
Javascript in a browser only really has a couple of effective scopes: function scope and global scope.
浏览器中的 Javascript 只有几个有效的作用域:函数作用域和全局作用域。
If a variable isn't in function scope, it's in global scope. And global variables are generally bad, so this is a construct to keep a library's variables to itself.
如果变量不在函数范围内,则它在全局范围内。并且全局变量通常是不好的,所以这是一种将库的变量保留给自身的构造。
回答by Joel
That's called a closure. It basically seals the code inside the function so that other libraries don't interfere with it. It's similar to creating a namespace in compiled languages.
这叫做闭包。它基本上密封了函数内部的代码,以便其他库不会干扰它。这类似于在编译语言中创建命名空间。
Example. Suppose I write:
例子。假设我写:
(function() {
var x = 2;
// do stuff with x
})();
Now other libraries cannot access the variable xI created to use in my library.
现在其他库无法访问x我创建的要在库中使用的变量。
回答by kennebec
You can use function closures as datain larger expressions as well, as in this method of determining browser support for some of the html5 objects.
您也可以在更大的表达式中使用函数闭包作为数据,就像在这种确定浏览器对某些 html5 对象的支持的方法中一样。
navigator.html5={
canvas: (function(){
var dc= document.createElement('canvas');
if(!dc.getContext) return 0;
var c= dc.getContext('2d');
return typeof c.fillText== 'function'? 2: 1;
})(),
localStorage: (function(){
return !!window.localStorage;
})(),
webworkers: (function(){
return !!window.Worker;
})(),
offline: (function(){
return !!window.applicationCache;
})()
}
回答by Coronus
In addition to keeping the variables local, one very handy use is when writing a library using a global variable, you can give it a shorter variable name to use within the library. It's often used in writing jQuery plugins, since jQuery allows you to disable the $ variable pointing to jQuery, using jQuery.noConflict(). In case it is disabled, your code can still use $ and not break if you just do:
除了将变量保持在本地之外,一个非常方便的用途是在使用全局变量编写库时,您可以为其指定一个较短的变量名称以在库中使用。它常用于编写 jQuery 插件,因为 jQuery 允许您使用 jQuery.noConflict() 禁用指向 jQuery 的 $ 变量。如果它被禁用,你的代码仍然可以使用 $ 而不会中断,如果你只是这样做:
(function($) { ...code...})(jQuery);
回答by Vivek Mehta
- To avoid clash with other methods/libraries in the same window,
- Avoid Global scope, make it local scope,
- To make debugging faster (local scope),
- JavaScript has function scope only, so it will help in compilation of codes as well.
- 为避免与同一窗口中的其他方法/库发生冲突,
- 避免全局作用域,使其成为局部作用域,
- 为了使调试更快(本地范围),
- JavaScript 只有函数作用域,所以它也有助于代码的编译。
回答by Neha Jain
We should also use 'use strict' in the scope function to make sure that the code should be executed in "strict mode". Sample code shown below
我们还应该在作用域函数中使用“use strict”来确保代码应该在“严格模式”下执行。示例代码如下所示
(function() {
'use strict';
//Your code from here
})();

