模块模式的要点?
Point of module pattern?
模块的主要好处(我听说过)是它们隐藏了私有变量。
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解决了什么?
没有模块,你必须使用另一个变量。
var Test = new test(someX);
然后以 Test.replace
.
的形式访问属性
有了模块模式,你可以简单地使用
Module.publicProperty
加载后立即。
privateProperty would be hidden anyway
不,如果没有 IIFE,privateProperty
将是全局范围的 属性。
除非你谈论的是模块加载器,它(在幕后)基本上与 IIFE 做的一样,它将整个文件包装在一个函数中,有点像:
var factory = Function("require, module, exports, global", yourFileBody );
然后用正确的值调用工厂;这也是你拥有这些机制的原因;因为它们是作为函数参数注入的。
这就是这些 "private" 属性不会污染全局命名空间的原因。
编辑:
I tried an example without any module.exports, but I still don't understand what problem point IIFEs are solving. I posted the example in Edit 2
test1 是工厂,不是模块。让我们移除工厂并提取生成的模块,然后做一些小的改动,让这个私有状态有意义。 (将 public属性 转换为函数 "speak" 并在那里实际使用私有 property/value/state)
//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坏了。它应该说 "Hello World" ...我希望有一种方法可以让我的 private
属性 真正私密,这样其他人就不会乱用它。
https://jsfiddle.net/crkguf6b/
@jro,你现在明白了吗?这样的工厂封装了私有状态,这样它就不会污染全局命名空间,也不会被一些不同的代码弄得一团糟;同时只暴露一个 public API。
您开始提问的 IIFE 实际上是一个匿名工厂,它会立即被调用以创建此 Object/Module 的一个实例,然后获取 GC。如顶部所示,模块加载器以相同的方式执行此操作。他们根据您的 JS 文件在幕后(或在预处理步骤中)创建这些工厂,并在必要时调用它们。
结论:
这不是语言固有的,private属性 是私有的。是 "artificial"。如果没有将 JS 文件包装在函数中的模块加载器,没有工厂,也没有 IIFE,private属性 就不是私有的。
也许这会随着 ES6 模块而改变。也许它会得到 JS 的固有部分,每个文件都被视为一个单独的模块,因此文件中的普通 var foo;
不会在全局命名空间中结束, 但在现在不是了。
您的 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>
这与任何东西的属性无关,它与脚本中的全局范围有关。
模块的主要好处(我听说过)是它们隐藏了私有变量。
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解决了什么?
没有模块,你必须使用另一个变量。
var Test = new test(someX);
然后以 Test.replace
.
有了模块模式,你可以简单地使用
Module.publicProperty
加载后立即。
privateProperty would be hidden anyway
不,如果没有 IIFE,privateProperty
将是全局范围的 属性。
除非你谈论的是模块加载器,它(在幕后)基本上与 IIFE 做的一样,它将整个文件包装在一个函数中,有点像:
var factory = Function("require, module, exports, global", yourFileBody );
然后用正确的值调用工厂;这也是你拥有这些机制的原因;因为它们是作为函数参数注入的。
这就是这些 "private" 属性不会污染全局命名空间的原因。
编辑:
I tried an example without any module.exports, but I still don't understand what problem point IIFEs are solving. I posted the example in Edit 2
test1 是工厂,不是模块。让我们移除工厂并提取生成的模块,然后做一些小的改动,让这个私有状态有意义。 (将 public属性 转换为函数 "speak" 并在那里实际使用私有 property/value/state)
//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坏了。它应该说 "Hello World" ...我希望有一种方法可以让我的 private
属性 真正私密,这样其他人就不会乱用它。
https://jsfiddle.net/crkguf6b/
@jro,你现在明白了吗?这样的工厂封装了私有状态,这样它就不会污染全局命名空间,也不会被一些不同的代码弄得一团糟;同时只暴露一个 public API。 您开始提问的 IIFE 实际上是一个匿名工厂,它会立即被调用以创建此 Object/Module 的一个实例,然后获取 GC。如顶部所示,模块加载器以相同的方式执行此操作。他们根据您的 JS 文件在幕后(或在预处理步骤中)创建这些工厂,并在必要时调用它们。
结论:
这不是语言固有的,private属性 是私有的。是 "artificial"。如果没有将 JS 文件包装在函数中的模块加载器,没有工厂,也没有 IIFE,private属性 就不是私有的。
也许这会随着 ES6 模块而改变。也许它会得到 JS 的固有部分,每个文件都被视为一个单独的模块,因此文件中的普通 var foo;
不会在全局命名空间中结束, 但在现在不是了。
您的 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>
这与任何东西的属性无关,它与脚本中的全局范围有关。