Javascript - 自执行函数:如果我可以创建不带自执行函数的本地作用域,为什么还要使用它们?
Javascript - self-executing functions : why to use them if I can create local scope with not self-executing functions?
我知道这里和其他地方有很多关于自执行函数的帖子,但阅读帖子后我仍然有一些疑问。
为什么我要将自执行函数分配给变量?如果看起来他们无论如何都会执行自己。
var myFunc=(function() {
console.log('Hello World');
})();
我读了很多,使用自执行函数的原因是为了保持变量私有。如果我有一个非自执行函数,那么我在该函数中定义的所有内容都将是私有的?!
(function() {
var name="my Name"
console.log(name);
})();
vs.
function() {
var name="my Name"
console.log(name);
};
//its the same
所以我不太明白自执行函数是如何保持局部范围的(因为你可以使用非自执行函数来做到这一点)所以我看到的唯一原因是当你想自动执行时使用它们页面加载示例。
谢谢!
还有一个问题:
var test=(function myFunc(){
var name="Hello World"
return {
test1: function(){
return name;
},
test2:function(){
return name+"1"
}
}
})()
test.test1()
vs
var test=function myFunc(){
var name="Hello World"
return {
test1: function(){
return name;
},
test2:function(){
return name+"1"
}
}
}
test.test1()
--> 这里到底发生了什么,因为 IIFE 我实际上可以执行 test.test1() 而不是使用常规函数?
如果那个 IIFE 没有 return 任何东西,那么将它分配给任何东西确实是绝对没有用的。虽然当然可能有 IIFE 的例子 returning 你以后想用的东西;在这种情况下,IIFE 是一个私有范围,用于设置一些对象,例如:
var foo = (function () {
var bar = 'something';
// here be dragons
return baz;
})();
这为您提供了 assemble baz
的私有作用域,而不会不必要地将临时变量泄漏到全局作用域中。
这些示例没有区别,只是第二个示例不执行,因此从不执行任何操作。范围界定和范围界定的目的没有改变。
当你想保持你的范围被包含时,你通常将你的函数包装在一个匿名函数中。这也是仍然很流行的模块模式的一部分:
https://toddmotto.com/mastering-the-module-pattern/
然后您可以将 IIFE 的结果分配给一个变量,这样您的作用域就只能通过调用该变量来访问。
myScope.myLocallyScopedProperty or myScope[myLocallyScopedProperty]
您的其他函数需要手动调用,并且也可以从任何地方访问。
我建议阅读 Todd Moto 的文章,它解释了很多。
首先,简而言之,这些不是自动执行的功能。 (那将是一个 递归 函数。)这些是内联调用的函数表达式 (IIFE)。 函数不调用自身,表达式调用函数。
why would I ever assign a self-executing function to a variable?
那不是该代码的作用。它将调用 IIFE 的 result 分配给变量。您可以在需要该结果时使用它,例如:
var x = (function() {
var n = 0;
return {
increment: function() { return ++n; }
};
})();
console.log(typeof x); // "object"
console.log(x.increment()); // 1
console.log(x.increment()); // 2
x
不接收 IIFE,它接收 IIFE returns 的内容——在本例中,是一个带有函数的对象。
I read a lot that the reason to use self-executing functions is to keep variables private. If I have a not self-executing function, everything I define inside that function is gonna be private anyways?!
是的,没错。当您只需要执行 IIFE 中的操作 一次 时,您可以使用 IIFE。否则,绝对可以定义函数,为其命名,然后在任何需要的地方重用它。函数内部的变量确实是私有的(除非以某种方式暴露),并且特定于对函数的每次调用。
In the form of IIFE (or immediately invoked function expressions), they can then be used to create plugins or used as namespaces and attached to window / jquery / or other global level object for use later.
当你命名一个函数时,比如将匿名函数分配给一个变量,你可以稍后通过用括号调用变量来使用它,在你的例子中,用
定义了 myFunc
var myFunc=(function() {
console.log('Hello World');
});
稍后在代码中将其用作myFunc()
;
在您的示例中,您通过立即调用将函数的输出直接存储在变量中,并且没有要存储的输出。
因此,如果您稍后写入 console.log(myFunc);
,则会有 undefined
作为输出。
下面提到的代码示例中更好的 IIFE 示例。
(function() {
var name="my Name"
console.log(name);
})();
它执行,执行 console.log 就这样。在您的案例中,不向命名空间或全局对象添加任何内容。
你的最后一个例子定义了一个函数,然后没有执行它,并且由于它没有分配命名变量或名称,它给出了语法错误并且不能在以后的代码中使用。所以,下面的例子是无用的。
function() {
var name="my Name"
console.log(name);
};
您又添加了两个 var test
= function myFunc
的示例。第一个可以与 test.test1()
一起正常工作。对于第二个,你需要先将 test 作为一个函数求值,然后调用它的函数,比如 test().test1()
.
1:将 IIFE 分配给局部变量对于类似这样的事情是有意义的:
var getID = (function () {
var id = 0;
return function () { return id++; };
})();
通过这种方式,您可以获得新的 ID,而不会 运行 从代码中的其他任何地方重置内部计数器的风险,除非重新声明变量。
2:基本上你通过创建一个函数来创建范围。但是,如果您不执行它,那么它什么也不会做。所以如果你有:
function () { return 'foo' };
如果没有赋值给变量或者没有名字,你想怎么调用呢?它本身不会做任何事情,因为它没有被调用。类似的东西是死代码,可以安全地删除。
你的第一件事毫无意义:
var myFunc = =(function() {
console.log('Hello World');
})();
myFunc
不是函数,它是 undefined
。
在我看来,自执行函数的意义在于打包一些必须立即执行的代码。
var p1=1, p2=2, obj = {
prop: (function(x,y){ return x+y;})(p1, p2)
}
或
避免覆盖已经定义的 functions/objects 以防您的脚本将被插入到一个已经存在的应用程序中,并且如果您愿意,还可以创建一种私有方法:
function aFunction() {
console.log('a code');
}
(function(w) {
function aFunction() {
console.log('b code');
}
w.run = function() {
aFunction();
};
})(window)
aFunction();
run();
我猜你在这里错过了什么。只是为了弄清楚基本的事情——如果你将一个自执行函数分配给一个变量,此时执行的函数的实际 return value
被分配给变量而不是函数本身。
var myFunc = (function() {
console.log('Hello World');
})();
myFunc(); // will throw error: TypeError: myFunc is not a function
myFunc === undefined
var myFunc = (function() {
console.log('Hello World');
return 'japp';
})();
myFunc(); // will throw error: TypeError: myFunc is not a function
myFunc === 'japp'
那么为什么会出现这种模式?
IIFE 对
非常有用
限制范围
如果你声明
var test = 'test'; // var test actually will be assigned as a property of the current context (this)
window.test = 'test'; // so you pollute the global namespace which is not a good practice
所以这样会好很多
(function() {
var test = 'test';
})();
使用 IIF 的另一个非常好的事情是您可以使用 "privates"
实现设计
var myFunc;
(function() {
var i = 0; // i is available for myFunc with private access
myFunc = function() { console.log( ++i ) };
})();
myFunc(); // logs 1
myFunc(); // logs 2
您使用自执行函数仅在范围外公开您需要的内容。我想我有一个比较清楚的例子:
let myObject = (function(){
let privateVariable = "I'm private";
function privateMethod() {
//private method
};
function methodToExpose() {
//this method I will expose
}
//what is returned here, is what is public
return {
PublicMethod: methodToExpose
//other public properties
}
}());
所以,该函数立即执行,发生的事情是我有一个由我从函数返回的内容定义的对象。
我可以给你的另一个例子是在闭包中保留当前作用域的变量,但你不会真正使用它那么多,因为我们现在有 let
。一个实际例子:
<span id="1">old</span>
<span id="2">old</span>
<span id="3">old</span>
<span id="4">old</span>
<script>
var toPrint = "";
for (var i = 1; i <= 4; i++) {
toPrint = "new: " + i;
document.getElementById(i.toString()).addEventListener('click', function(event){ event.target.innerHTML = toPrint; })
}
</script>
当您点击跨度时,该值将替换为值... "new: 4"!
那是因为当你完成执行时,这就是 toPrint 的值。分配给 click 事件的函数检索 toPrint,并且在检索它时,它是 "new: 4"。我们用闭包解决这个问题:
<span id="1">old</span>
<span id="2">old</span>
<span id="3">old</span>
<span id="4">old</span>
<script>
var toPrint = "";
for (var i = 1; i <= 4; i++) {
toPrint = "new: " + i;
document.getElementById(i.toString()).addEventListener('click', function(event){
var currPrint = toPrint;
return function(event){ event.target.innerHTML = currPrint ; };
}())
}
</script>
通过使用自执行函数,我们将 toPrint 的当前值保存在局部范围内的 currPrint 变量中。当我们稍后点击一个 span 时,分配给点击的函数甚至会使用变量 currPrint,它包含 toPrint 在函数被分配时的值,而不是 toPrint 在完成执行时的值。
请注意,这也可以通过使用 let 而不是 var 来解决,但它仍然是自执行函数的一个示例:)
我知道这里和其他地方有很多关于自执行函数的帖子,但阅读帖子后我仍然有一些疑问。
为什么我要将自执行函数分配给变量?如果看起来他们无论如何都会执行自己。
var myFunc=(function() { console.log('Hello World'); })();
我读了很多,使用自执行函数的原因是为了保持变量私有。如果我有一个非自执行函数,那么我在该函数中定义的所有内容都将是私有的?!
(function() { var name="my Name" console.log(name); })(); vs. function() { var name="my Name" console.log(name); }; //its the same
所以我不太明白自执行函数是如何保持局部范围的(因为你可以使用非自执行函数来做到这一点)所以我看到的唯一原因是当你想自动执行时使用它们页面加载示例。
谢谢!
还有一个问题:
var test=(function myFunc(){
var name="Hello World"
return {
test1: function(){
return name;
},
test2:function(){
return name+"1"
}
}
})()
test.test1()
vs
var test=function myFunc(){
var name="Hello World"
return {
test1: function(){
return name;
},
test2:function(){
return name+"1"
}
}
}
test.test1()
--> 这里到底发生了什么,因为 IIFE 我实际上可以执行 test.test1() 而不是使用常规函数?
如果那个 IIFE 没有 return 任何东西,那么将它分配给任何东西确实是绝对没有用的。虽然当然可能有 IIFE 的例子 returning 你以后想用的东西;在这种情况下,IIFE 是一个私有范围,用于设置一些对象,例如:
var foo = (function () { var bar = 'something'; // here be dragons return baz; })();
这为您提供了 assemble
baz
的私有作用域,而不会不必要地将临时变量泄漏到全局作用域中。这些示例没有区别,只是第二个示例不执行,因此从不执行任何操作。范围界定和范围界定的目的没有改变。
当你想保持你的范围被包含时,你通常将你的函数包装在一个匿名函数中。这也是仍然很流行的模块模式的一部分:
https://toddmotto.com/mastering-the-module-pattern/
然后您可以将 IIFE 的结果分配给一个变量,这样您的作用域就只能通过调用该变量来访问。
myScope.myLocallyScopedProperty or myScope[myLocallyScopedProperty]
您的其他函数需要手动调用,并且也可以从任何地方访问。
我建议阅读 Todd Moto 的文章,它解释了很多。
首先,简而言之,这些不是自动执行的功能。 (那将是一个 递归 函数。)这些是内联调用的函数表达式 (IIFE)。 函数不调用自身,表达式调用函数。
why would I ever assign a self-executing function to a variable?
那不是该代码的作用。它将调用 IIFE 的 result 分配给变量。您可以在需要该结果时使用它,例如:
var x = (function() {
var n = 0;
return {
increment: function() { return ++n; }
};
})();
console.log(typeof x); // "object"
console.log(x.increment()); // 1
console.log(x.increment()); // 2
x
不接收 IIFE,它接收 IIFE returns 的内容——在本例中,是一个带有函数的对象。
I read a lot that the reason to use self-executing functions is to keep variables private. If I have a not self-executing function, everything I define inside that function is gonna be private anyways?!
是的,没错。当您只需要执行 IIFE 中的操作 一次 时,您可以使用 IIFE。否则,绝对可以定义函数,为其命名,然后在任何需要的地方重用它。函数内部的变量确实是私有的(除非以某种方式暴露),并且特定于对函数的每次调用。
In the form of IIFE (or immediately invoked function expressions), they can then be used to create plugins or used as namespaces and attached to window / jquery / or other global level object for use later.
当你命名一个函数时,比如将匿名函数分配给一个变量,你可以稍后通过用括号调用变量来使用它,在你的例子中,用
定义了 myFuncvar myFunc=(function() {
console.log('Hello World');
});
稍后在代码中将其用作myFunc()
;
在您的示例中,您通过立即调用将函数的输出直接存储在变量中,并且没有要存储的输出。
因此,如果您稍后写入 console.log(myFunc);
,则会有 undefined
作为输出。
下面提到的代码示例中更好的 IIFE 示例。
(function() {
var name="my Name"
console.log(name);
})();
它执行,执行 console.log 就这样。在您的案例中,不向命名空间或全局对象添加任何内容。
你的最后一个例子定义了一个函数,然后没有执行它,并且由于它没有分配命名变量或名称,它给出了语法错误并且不能在以后的代码中使用。所以,下面的例子是无用的。
function() {
var name="my Name"
console.log(name);
};
您又添加了两个 var test
= function myFunc
的示例。第一个可以与 test.test1()
一起正常工作。对于第二个,你需要先将 test 作为一个函数求值,然后调用它的函数,比如 test().test1()
.
1:将 IIFE 分配给局部变量对于类似这样的事情是有意义的:
var getID = (function () {
var id = 0;
return function () { return id++; };
})();
通过这种方式,您可以获得新的 ID,而不会 运行 从代码中的其他任何地方重置内部计数器的风险,除非重新声明变量。
2:基本上你通过创建一个函数来创建范围。但是,如果您不执行它,那么它什么也不会做。所以如果你有:
function () { return 'foo' };
如果没有赋值给变量或者没有名字,你想怎么调用呢?它本身不会做任何事情,因为它没有被调用。类似的东西是死代码,可以安全地删除。
你的第一件事毫无意义:
var myFunc = =(function() {
console.log('Hello World');
})();
myFunc
不是函数,它是 undefined
。
在我看来,自执行函数的意义在于打包一些必须立即执行的代码。
var p1=1, p2=2, obj = {
prop: (function(x,y){ return x+y;})(p1, p2)
}
或 避免覆盖已经定义的 functions/objects 以防您的脚本将被插入到一个已经存在的应用程序中,并且如果您愿意,还可以创建一种私有方法:
function aFunction() {
console.log('a code');
}
(function(w) {
function aFunction() {
console.log('b code');
}
w.run = function() {
aFunction();
};
})(window)
aFunction();
run();
我猜你在这里错过了什么。只是为了弄清楚基本的事情——如果你将一个自执行函数分配给一个变量,此时执行的函数的实际 return value
被分配给变量而不是函数本身。
var myFunc = (function() {
console.log('Hello World');
})();
myFunc(); // will throw error: TypeError: myFunc is not a function
myFunc === undefined
var myFunc = (function() {
console.log('Hello World');
return 'japp';
})();
myFunc(); // will throw error: TypeError: myFunc is not a function
myFunc === 'japp'
那么为什么会出现这种模式?
IIFE 对
非常有用限制范围 如果你声明
var test = 'test'; // var test actually will be assigned as a property of the current context (this) window.test = 'test'; // so you pollute the global namespace which is not a good practice
所以这样会好很多
(function() { var test = 'test'; })();
使用 IIF 的另一个非常好的事情是您可以使用 "privates"
实现设计var myFunc; (function() { var i = 0; // i is available for myFunc with private access myFunc = function() { console.log( ++i ) }; })(); myFunc(); // logs 1 myFunc(); // logs 2
您使用自执行函数仅在范围外公开您需要的内容。我想我有一个比较清楚的例子:
let myObject = (function(){
let privateVariable = "I'm private";
function privateMethod() {
//private method
};
function methodToExpose() {
//this method I will expose
}
//what is returned here, is what is public
return {
PublicMethod: methodToExpose
//other public properties
}
}());
所以,该函数立即执行,发生的事情是我有一个由我从函数返回的内容定义的对象。
我可以给你的另一个例子是在闭包中保留当前作用域的变量,但你不会真正使用它那么多,因为我们现在有 let
。一个实际例子:
<span id="1">old</span>
<span id="2">old</span>
<span id="3">old</span>
<span id="4">old</span>
<script>
var toPrint = "";
for (var i = 1; i <= 4; i++) {
toPrint = "new: " + i;
document.getElementById(i.toString()).addEventListener('click', function(event){ event.target.innerHTML = toPrint; })
}
</script>
当您点击跨度时,该值将替换为值... "new: 4"! 那是因为当你完成执行时,这就是 toPrint 的值。分配给 click 事件的函数检索 toPrint,并且在检索它时,它是 "new: 4"。我们用闭包解决这个问题:
<span id="1">old</span>
<span id="2">old</span>
<span id="3">old</span>
<span id="4">old</span>
<script>
var toPrint = "";
for (var i = 1; i <= 4; i++) {
toPrint = "new: " + i;
document.getElementById(i.toString()).addEventListener('click', function(event){
var currPrint = toPrint;
return function(event){ event.target.innerHTML = currPrint ; };
}())
}
</script>
通过使用自执行函数,我们将 toPrint 的当前值保存在局部范围内的 currPrint 变量中。当我们稍后点击一个 span 时,分配给点击的函数甚至会使用变量 currPrint,它包含 toPrint 在函数被分配时的值,而不是 toPrint 在完成执行时的值。
请注意,这也可以通过使用 let 而不是 var 来解决,但它仍然是自执行函数的一个示例:)