提问人:Ej. 提问时间:2/27/2009 最后编辑:thatpaintingelephantEj. 更新时间:12/26/2022 访问量:226118
javascript 中自执行函数的目的是什么?
What is the purpose of a self executing function in javascript?
问:
在 javascript 中,您希望何时使用它:
(function(){
//Bunch of code...
})();
在此之上:
//Bunch of code...
答:
命名空间。JavaScript 的作用域是函数级的。
评论
IIRC 它允许您创建私有属性和方法。
这一切都与变量范围有关。默认情况下,在自执行函数中声明的变量仅可用于自执行函数中的代码。这允许编写代码,而无需担心变量在其他 JavaScript 代码块中的命名方式。
例如,正如亚历山大在评论中提到的:
(function() {
var foo = 3;
console.log(foo);
})();
console.log(foo);
这将首先记录,然后在下一个错误上抛出错误,因为未定义。3
console.log
foo
评论
function(){ var foo = 3; alert(foo); }; alert(foo);
{ let foo = 3 }
由于 Javascript 中的函数是第一类对象,因此通过以这种方式定义它,它有效地定义了一个类似于 C++ 或 C# 的“类”。
该函数可以定义局部变量,并在其中包含函数。内部函数(实际上是实例方法)将有权访问局部变量(实际上是实例变量),但它们将与脚本的其余部分隔离。
也许是范围隔离。这样函数声明中的变量就不会污染外部命名空间。
当然,在一半的 JS 实现中,它们无论如何都会。
评论
一个区别是,您在函数中声明的变量是局部的,因此当您退出函数时,它们会消失,并且它们不会与其他或相同代码中的其他变量冲突。
是否有参数并且“一堆代码”返回一个函数?
var a = function(x) { return function() { document.write(x); } }(something);
关闭。分配给 的函数使用的值。 可以有一些不同的值(for 循环),并且每次 A 都有一个新函数。something
a
something
评论
var x = something;
x
x
document.write(something)
自我调用(也称为 auto-invocation) 是当函数 在其 定义。这是一个核心模式和 是许多人的基础 JavaScript 的其他模式 发展。
我是:)的忠实粉丝因为:
- 它将代码保持在最低限度
- 它强制将行为与演示分开
- 它提供了一个闭包,可以防止命名冲突
非常 - (为什么你应该说它好?
- 这是关于一次定义和执行一个函数。
- 您可以让该自执行函数返回一个值,并将该函数作为参数传递给另一个函数。
- 它有利于封装。
- 它也适用于块范围。
- 是的,您可以将所有 .js 文件包含在自执行函数中,并且可以防止全局命名空间污染。;)
更多内容请点击此处。
评论
我简直不敢相信没有一个答案提到隐含的全局。
该结构不能防止隐含的全局变量,对我来说,这是更大的问题,请参阅 http://yuiblog.com/blog/2006/06/01/global-domination/(function(){})()
基本上,功能块确保您定义的所有依赖“全局变量”都仅限于您的程序,它不能保护您免受定义隐式全局变量的影响。JSHint 等可以提供有关如何防御此行为的建议。
更简洁的语法提供类似级别的保护,并且在“公共”页面上时可以包装在功能块中。(请参阅 Ember.js 或 SproutCore 以获取使用此构造的库的实际示例)var App = {}
就属性而言,除非您正在创建公共框架或库,否则它们被高估了,但如果您需要实现它们,Douglas Crockford 有一些好主意。private
评论
简单。看起来很正常,几乎令人欣慰:
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
但是,如果我在我的页面中包含一个非常方便的 javascript 库,将高级字符转换为其基本表示形式,该怎么办?
等。。。什么?
我的意思是,如果有人输入一个带有某种口音的字符,但我只想在我的程序中输入“英语”字符 A-Z?井。。。西班牙语“ñ”和法语“é”字符可以翻译成“n”和“e”的基本字符。
所以一个好人写了一个全面的字符转换器,我可以把它包含在我的网站中......我把它包括在内。
一个问题:它有一个叫做“name”的函数,与我的函数相同。
这就是所谓的碰撞。我们在同一作用域中声明了两个具有相同名称的函数。我们想避免这种情况。
因此,我们需要以某种方式确定代码的范围。
在 javascript 中确定代码范围的唯一方法是将其包装在函数中:
function main() {
// We are now in our own sound-proofed room and the
// character-converter library's name() function can exist at the
// same time as ours.
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
}
这可能会解决我们的问题。现在一切都是封闭的,只能从我们的开口和闭合支架内访问。
我们有一个函数中的函数...这看起来很奇怪,但完全合法。
只有一个问题。我们的代码不起作用。
我们的变量永远不会回显到控制台中!userName
我们可以通过在现有代码块之后添加对函数的调用来解决这个问题......
function main() {
// We are now in our own sound-proofed room and the
// character-converter libarary's name() function can exist at the
// same time as ours.
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
}
main();
或者之前!
main();
function main() {
// We are now in our own sound-proofed room and the
// character-converter libarary's name() function can exist at the
// same time as ours.
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
}
第二个问题是:“main”这个名字还没有被使用的可能性有多大?...非常非常苗条。
我们需要更多的范围界定。以及自动执行我们的 main() 函数的某种方法。
现在我们来谈谈自动执行函数(或自动执行、自动运行等)。
((){})();
语法像罪恶一样笨拙。但是,它有效。
当您将函数定义包装在括号中,并包含参数列表(另一个集合或括号!)时,它充当函数调用。
因此,让我们再看一下我们的代码,其中包含一些自执行的语法:
(function main() {
var userName = "Sean";
console.log(name());
function name() {
return userName;
}
}
)();
因此,在您阅读的大多数教程中,您现在都会受到“匿名自动执行”或类似术语的轰炸。
经过多年的专业发展,我强烈建议您为调试目的而编写的每个函数都命名。
当出现问题(并且会出错)时,您将检查浏览器中的回溯。当堆栈跟踪中的条目具有名称时,缩小代码问题的范围总是更容易!
评论
:)
javascript 中的自调用函数:
自调用表达式会自动调用(启动),而不会被调用。自调用表达式在创建后立即调用。这主要用于避免命名冲突以及实现封装。在此函数之外无法访问变量或声明的对象。为了避免最小化(filename.min)的问题,请始终使用自执行函数。
下面是一个关于自我调用匿名函数如何有用的可靠示例。
for( var i = 0; i < 10; i++ ) {
setTimeout(function(){
console.log(i)
})
}
输出:10, 10, 10, 10, 10...
for( var i = 0; i < 10; i++ ) {
(function(num){
setTimeout(function(){
console.log(num)
})
})(i)
}
输出:0, 1, 2, 3, 4...
评论
let
var
看起来这个问题已经准备好了,但我还是会发布我的意见。
我知道什么时候我喜欢使用自动执行函数。
var myObject = {
childObject: new function(){
// bunch of code
},
objVar1: <value>,
objVar2: <value>
}
该函数允许我使用一些额外的代码来定义 childObjects 属性和属性,以获得更简洁的代码,例如设置常用变量或执行数学方程式;哦!或错误检查。而不是局限于嵌套对象实例化语法...
object: {
childObject: {
childObject: {<value>, <value>, <value>}
},
objVar1: <value>,
objVar2: <value>
}
一般来说,编码有很多晦涩难懂的方式来做很多同样的事情,让你想知道,“何必呢?但是,新的情况不断出现,您不能再仅依靠基本/核心原则。
(function(){
var foo = {
name: 'bob'
};
console.log(foo.name); // bob
})();
console.log(foo.name); // Reference error
实际上,上面的函数将被视为没有名称的函数表达式。
用右括号和左括号包装函数的主要目的是避免污染全局空间。
函数表达式中的变量和函数变为私有(即,它们在函数外部不可用。
我已经阅读了所有答案,这里缺少一些非常重要的东西,我会亲吻。有两个主要原因,为什么我需要自执行匿名函数,或者更好地说“立即调用函数表达式 (IIFE)”:
- 更好的命名空间管理(避免命名空间污染 -> JS 模块)
- 闭包(模拟私有类成员,从 OOP 中得知)
第一个已经解释得很好。对于第二个,请学习以下示例:
var MyClosureObject = (function (){
var MyName = 'Michael Jackson RIP';
return {
getMyName: function () { return MyName;},
setMyName: function (name) { MyName = name}
}
}());
注意事项1:我们没有将函数赋值给 ,而是将函数赋值给 ,更不是将函数赋值给 。请注意最后一行。MyClosureObject
()
注意事项2:关于 Javascript 中的函数,您还需要了解的是,内部函数可以访问函数的参数和变量,它们是在内部定义的。
让我们尝试一些实验:
我可以开始使用并且它有效:MyName
getMyName
console.log(MyClosureObject.getMyName());
// Michael Jackson RIP
以下巧妙的方法行不通:
console.log(MyClosureObject.MyName);
// undefined
但是我可以设置另一个名称并获得预期的结果:
MyClosureObject.setMyName('George Michael RIP');
console.log(MyClosureObject.getMyName());
// George Michael RIP
编辑:在上面的示例中,它被设计为不带前缀使用,因此按照惯例,它不应该大写。MyClosureObject
new
评论
自执行函数用于管理变量的作用域。
变量的作用域是定义变量的程序区域。
全局变量具有全局作用域;它在 JavaScript 代码中的任何地方都定义,可以从脚本中的任何位置访问,甚至可以在函数中访问。另一方面,在函数中声明的变量仅在函数主体中定义。 它们是局部变量,具有局部作用域,并且只能在该函数中访问。函数参数也算作局部变量,并且仅在函数主体中定义。
如下图所示,您可以访问函数内部的全局变量变量,并注意在函数的主体中,局部变量优先于同名的全局变量。
var globalvar = "globalvar"; // this var can be accessed anywhere within the script
function scope() {
alert(globalvar);
var localvar = "localvar"; //can only be accessed within the function scope
}
scope();
因此,基本上,自执行函数允许编写代码,而不用担心变量在其他 javascript 代码块中的命名方式。
简短的回答是:防止全球(或更高)范围的污染。
IIFE(立即调用的函数表达式)是将脚本编写为插件、附加组件、用户脚本或任何预期与其他人的脚本一起使用的脚本的最佳实践。这可确保您定义的任何变量不会对其他脚本产生不良影响。
这是写 IIFE 表达式的另一种方式。我个人更喜欢以下方法:
void function() {
console.log('boo!');
// expected output: "boo!"
}();
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/void
从上面的例子中可以清楚地看出,IIFE 也会影响效率和性能,因为预计只运行一次的函数将被执行一次,然后永远被倾倒到虚空中。这意味着函数或方法声明不会保留在内存中。
评论
void
首先你必须访问 MDN IIFE,现在关于这个的一些要点
- 这是立即调用的函数表达式。因此,当您的 javascript 文件从 HTML 调用此函数时,会立即调用。
- 这样可以防止访问 IIFE 习语中的变量,也可以防止污染全局范围。
鉴于您的简单问题:“在 javascript 中,您想什么时候使用它:...”
我喜欢 @ken_browning 和 @sean_holding 的答案,但这是另一个我没有看到提及的用例:
let red_tree = new Node(10);
(async function () {
for (let i = 0; i < 1000; i++) {
await red_tree.insert(i);
}
})();
console.log('----->red_tree.printInOrder():', red_tree.printInOrder());
其中 Node.insert 是一些异步操作。
我不能在我的函数声明中没有 async 关键字的情况下调用 await,而且我不需要命名函数供以后使用,但需要等待该插入调用,或者我需要一些其他更丰富的功能(谁知道呢?
您可以使用此函数返回值:
var Test = (function (){
const alternative = function(){ return 'Error Get Function '},
methods = {
GetName: alternative,
GetAge:alternative
}
// If the condition is not met, the default text will be returned
// replace to 55 < 44
if( 55 > 44){
// Function one
methods.GetName = function (name) {
return name;
};
// Function Two
methods.GetAge = function (age) {
return age;
};
}
return methods;
}());
// Call
console.log( Test.GetName("Yehia") );
console.log( Test.GetAge(66) );
评论
此方法用于闭包。阅读此链接,了解有关关闭的更多信息。
评论
下一个:嵌套函数中的局部变量
评论