模块的主要好处(我听说)是隐藏私有变量。
var Module = (function() {
var privateProperty = 'foo';
return {
publicProperty: '...',
publicMethod: function(args) { ... }
}
})();
但是IIFE没有必要这样做。如果您只是将其删除,那么无论如何都会隐藏privateProperty。那么为什么要使用IIFE呢?我试图理解其基本原理。
编辑:
我一直在阅读没有IIFE的privateProperty将成为全球范围的一部分。我认为这是错误的。
如果我执行以下操作:
console.log(privateProperty); // => Reference Error: privateProperty isn't defined
我收到了引用错误。如果我这样做:
console.log(Module.privateProperty) // => undefined
我未定义。如果我这样做:
var mod = new Module();
console.log(mod.privateProperty); // => undefined
我未定义。全局范围无法访问JS中的本地范围。
编辑2:
test.js
var test = (function() {
var privateProperty = 'foo';
return {
publicProperty: 'bar',
}
})();
test.js
var test1 = function() {
var privateProperty = 'foo';
return {
publicProperty: 'bar',
}
};
的index.html ...
<script src="./test.js"></script>
<script src="./test1.js"></script>
<script>
console.log(test.privateProperty); // => undefined
console.log(test1.privateProperty); // => undefined
</script>
当我尝试上述操作时,在任何一种情况下我都无法访问privateProperty。人们谈论的名字碰撞在哪里?什么是IIFE解决?
答案 0 :(得分:1)
privateProperty无论如何都会隐藏
不,如果没有IIFE,privateProperty
将成为全球范围内的财产。
除非你在谈论模块加载器,它(在幕后)基本上和IIFE一样,它将整个文件包装在一个函数中,有点像:
var factory = Function("require, module, exports, global", yourFileBody );
然后使用正确的值调用工厂;这也是你拥有这些机制的原因;因为它们是作为函数参数注入的。
这些&#34;私人&#34;属性不会污染全局命名空间。
修改强>
我尝试了一个没有任何module.exports的例子,但我仍然不明白IIFE正在解决什么问题。我在Edit 2
中发布了这个例子
test1是工厂,而不是模块。让我们删除工厂并提取生成的模块,让我们做一些小改动,以便这个私有状态有意义。 (将publicProperty变成一个函数&#34;说&#34;并实际使用私有属性/值/状态)
//the generted Module boils down to:
var test1 = {
name: "test1",
speak() {
return this.name + " says " + private;
}
};
//and the private state also has to be kept somewhere:
var private = "Hello World";
现在让我们检查模块
console.log("test1", test1);
console.log("test1.speak()", test1.speak());
console.log("test1.private", test1.private);
很好,一切都如预期一样 但等等,这是什么?
console.log(
"Look here:",
private,
this.private,
window.private
)
哦,不,有人暴露了我的私有财产!每个人都可以看到它 如果其他脚本也定义了私有属性,会发生什么?
var private = "Bye Folks";
var test1 = {
name: "test2",
speak() {
return this.name + " says " + private;
}
};
console.log("test2", test2);
console.log("test2.speak():", test2.speak());
很好,很好。怎么样......
console.log("test1.speak():", test1.speak());
哦不,test1坏了。它应该说&#34; Hello World&#34; ......我希望有办法让我的private
财产真正私密,这样别人就不会搞砸了。
https://jsfiddle.net/crkguf6b/
@jro,你现在明白了吗?这样的工厂封装了私有状态,因此它不会污染全局命名空间,并且它不会被一些不同的代码弄乱;同时只公开一个公共API。 您开始提问的IIFE实际上是一个匿名工厂,它立即被调用以创建该对象/模块的一个实例,然后获取GC。如顶部所示,模块加载器以相同的方式执行。他们在JS文件的幕后(或在预处理步骤中)创建这些工厂,并在必要时调用它们。<强>结论:强>
该语言不是固有的,私有属性是私有的。它&#34;人工&#34;。没有将JS文件包装在函数中的模块加载器,没有工厂,没有IIFE,privateProperty也不会私有。
也许这会随着ES6模块而改变。也许它将获得JS的内在部分,每个文件都被视为一个单独的模块,因此文件中的普通var foo;
不会在全局命名空间中结束,但是在那一刻它没有。
答案 1 :(得分:1)
您的test1
文件包含普通函数,而不是模块模式而不是无模块模式。试试这个:
<script>
var testA = (function() {
var privateVariable = 'bar A';
return {
publicProperty: 'foo' + privateVariable
}
})();
</script>
<script>
var privateVariable = 'bar B';
var testB = {
publicProperty: 'foo' + privateVariable
};
</script>
<script>
console.log(testA.publicProperty); // => 'foobar A'
console.log(testB.publicProperty); // => 'foobar B'
console.log(privateVariable); // => 'bar B'
</script>
它不是关于任何东西的属性,而是关于脚本中的全局范围。
答案 2 :(得分:0)
如果没有该模块,则必须使用另一个变量。
var Test = new test(someX);
然后以Test.replace
访问属性。
使用模块模式,您只需使用
即可Module.publicProperty
加载后立即。