“泄漏”是什么意思?进入全球范围?
不久前,我提供了一个 JavaScript 设计模式(模块模式 - 见下文),这是我从 John Resig 示例中获得的 某人问题的解决方案的一部分,我收到了以下评论:
“……这个模式有点结束了 设计的但不是那么好。仍然 泄漏到全球范围。和你的 不向异步加载器开放。 但这比临时的要好 编码!”
所以...
如果“泄漏”到全局范围意味着“您的对象被附加到浏览器窗口(对象)”...那么所有内容都已经被附加(全局):
这个“泄漏”进入全局范围:
window.jQuery
…只需调用:window.jQuery
即可解析为 function();
这个“泄漏”到全局范围:
function HelloWorld() { alert(‘Howdy’); }
...只需调用:window.HelloWorld()
,您就会得到“Howdy”。
此“泄漏”到全局范围:
var myVariable = 10;
...只需调用:window.myVariable
,您将得到 10
如果评论者是正确的,则上述所有内容都“泄漏”进入全球范围。因此,就我个人而言,我认为没有办法不“泄漏”到全局范围,因为即使您的表单控件也存在于其中(也)。
因此,这是我的问题......
- “泄漏”是什么意思 全球范围?
- 为什么这么糟糕?
- 你如何避免它?
- 当想要创建持久化的时候 自定义对象,为什么是Module 图案(下)不好?
- 设计模式让你封装 复杂的逻辑,是封装 突然变坏只是因为我们 用 JavaScript 编写?
- 或者……这个评论者根本就是错的吗?
这是我上面提到的模块模式:
<script type="text/javascript">
var myNamespace = (function($) {
var publicInstances = {};
// ***********************
// myObject
publicInstances.myObject = myObject;
function myObject() {
/// <summary>A pointer to this</summary>
var self = this;
this.someProperty = new String();
this.initialize = function() {
/// your code here
}
this.someMethod = function() {
/// your code here
}
self.initialize();
}
return publicInstances;
})(jQuery);
jQuery(document).ready(function() {
// Use would look like
var myInstance = new myNamespace.myObject();
});
</script>
UPDATED:
I’m satisfied with the answers below and want to thank everyone for taking the time to comment.
回顾以下答案:
当局部作用域中使用的某些东西无意中可供全局作用域使用时(例如,窗口对象),就会发生“泄漏”到全局作用域中。这很糟糕,因为它会打开页面,导致潜在的命名冲突,从而可能导致变量解析为意外的值或类型。
故意将变量设置为全局变量不被视为“泄漏”。然而,需要正确地为对象命名空间,以减少所述命名冲突的可能性。
A while ago, I offered-up a JavaScript design pattern (the Module Pattern - see below) that I got from a John Resig example as part of a solution to someone’s question and I received the following comment:
“…that pattern is a bit over
engineered and not that good. Still
leaking into global-scope. and your
not opening yourself to async loaders.
But it is better then just ad-hoc
coding !”
So…
If “leaking” into global scope means “your object gets appended to the browsers window (object)”…then everything already gets appended (globally):
This “leaks” into global scope:
window.jQuery
…just call: window.jQuery
and it resolves as a function();
This “leaks” into global scope:
function HelloWorld() { alert(‘Howdy’); }
…just call: window.HelloWorld()
and you will get ‘Howdy’.
This “leaks” into global scope:
var myVariable = 10;
…just call: window.myVariable
and you will get 10
If the commenter is correct, then all the above “leak” into global-scope. So, personally, I don’t see a way NOT to “leak” into global-scope as even your form controls exists there (as well).
As such, here are my questions…
- What is meant by “leaking” into
global-scope? - Why is that bad?
- How do you avoid it?
- When wanting to create persistent
custom-objects, why is the Module
Pattern (below) bad? - Design patterns let you encapsulate
complex logic, is encapsulation
suddenly bad simply because we’re
writing in JavaScript? - Or...is this commenter simply wrong?
Here is the Module Pattern I Mentioned Above:
<script type="text/javascript">
var myNamespace = (function($) {
var publicInstances = {};
// ***********************
// myObject
publicInstances.myObject = myObject;
function myObject() {
/// <summary>A pointer to this</summary>
var self = this;
this.someProperty = new String();
this.initialize = function() {
/// your code here
}
this.someMethod = function() {
/// your code here
}
self.initialize();
}
return publicInstances;
})(jQuery);
jQuery(document).ready(function() {
// Use would look like
var myInstance = new myNamespace.myObject();
});
</script>
UPDATED:
I’m satisfied with the answers below and want to thank everyone for taking the time to comment.
TO RECAP THE ANSWERS BELOW:
"Leaking" into global-scope occurs when something used in local-scope is unintentionally made available to the global-scope (e.g. the window object). This is bad because it opens the page to potential naming collisions which could result in variables resolving to unexpected values or types.
Intentionally making a variable global is not considered a "leak". However, properly namespacing the object is required to reduce potential for said naming collisions.
You cannot avoid globally-scoped variables, but you can reduce the above risks by using asynchronous-loaders and defining-modules made available in plug-ins like RequireJS or Curl.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
“泄漏”到全局范围是指本地范围中使用的某些内容无意中可供全局范围使用。这意味着分配给当前范围内尚未定义的变量:
这很糟糕,因为可能存在命名冲突,导致变量具有与预期不同的值/类型。当您忘记对
for
语句中使用的变量使用var
关键字时,还可能导致旧版 Internet Explorer 中出现错误。我不会将故意将变量设置为全局变量归类为“泄漏”,因为这更像是您将其“倒入”全局范围。然而,这仍然经常被一些人认为是不好的做法(尽管我认为这有点夸张),因为与
window
对象的当前属性或其他脚本和库设置的变量仍然存在潜在的命名冲突。"Leaking" into global scope is when something used in a local scope is unintentionally made available to the global scope. That means assigning to a variable not already defined in the current scope:
It's bad because there could be naming collisions resulting in variables with different values/types than expected. It can also lead to a bug in older Internet Explorers when you forget to use the
var
keyword for a variable used in afor
statement.I wouldn't class intentionally making a variable global as "leaking", because it's more like you're "pouring" it into the global scope. However, this is still often considered bad practice by some (although I think that's a little melodramatic) because there are still potential naming collisions with current properties of the
window
object, or variables set by other scripts and libraries.[[短篇故事]]
不要创建全局变量并使用异步模块加载器,例如 requirejs 或 curl
[[长篇故事]]
该评论的结构很差。
模块系统没有任何问题。我根本就抱怨使用全局变量。 (我仍然认为完整的通用模块模式是臃肿的)。
是否应该避免所有全局变量是一个不同的问题,我认为这是风格问题。您可以使用异步加载器来传递模块,也可以使用
window
来传递模块。我的意思是你创建全局变量。最小化全局变量的使用是一种模式。在函数式编程中,全局变量可以为零,但这与使用全局模块是不同的模式。
全局存在任何状态都可能导致该状态被破坏。
你不能。不过,您可以最大限度地减少全局变量的数量。为了完全避免全局状态,您可以使用异步加载器。它们为您定义了一些随后可以使用的全局变量。
模块模式没有任何问题。问题是全局存储您的模块。问题在于全局命名空间。
现在我已经弄清楚了评论的意图,这个问题并不真正相关
该评论充其量是措辞不佳。我反对全局名称空间而不是模块,但没有正确说明这一点。
另一种方法是使用异步加载器并定义模块。这些可以缩小到两个全局变量。
定义
和require
。require = function(moduleName,callback)
这将获取一个模块,然后将其返回给您。
define = function(obj)
这定义了一个模块。
这里的概念是多文件代码如下:
[[Short story]]
Don't make global variables ever and use an async module loader like requirejs or curl
[[Long story]]
That comment was poorly structured.
There is nothing wrong with the module system. I was complaining about using global variables at all. (I still think the full generic module pattern is bloated).
Whether you should avoid all global variables is a different question and I think a matter of style. You can either use an async loader to pass modules around or using
window
to pass modules around.What I meant was your creating global variables. Minimising the use of global variables is a pattern. In functional style programming it's possible to have zero global variables but this is a different pattern from using global modules.
Having any state globally can cause that state to be corrupted.
You can't. You can minimize the amount of global variables though. To avoid having global state completely you can use asynchronous loaders. These define a few global variables for you that you can then use.
There is nothing wrong with the module pattern. The problem is storing your module globally. The issue is having global namespaces.
Now that I've cleared up the intent of the comment this question isn't really relevant
The comment was poorly phrased at best. I objected to global namespaces rather than modules, but did not state this properly.
The alternative is using asynchronous loaders and defining modules. These can be narrowed down to two global variables.
define
andrequire
.require = function(moduleName, callback)
This will get a module and then return it to you.
define = function(obj)
this defines a module.
The concept here is that you multi file code as follows:
您的模块仅“泄漏”它的名称空间持有者,因此这是相当可以接受的。
Your module only "leaks" it's namespace holder so it's pretty acceptable.
使用 RequireJS 的加载器示例:
在 utils.js 中定义实用程序模块:
在另一个模块(例如 math.js)中使用上述模块:
您可以在另一个文件中使用 math.js,例如 main.js:
您仍然可以拥有命名空间,并仍然让它们在模块内保持温暖和舒适:
namespace.js:
然后其余模块可以在定义期间使用此命名空间:
或者在运行时,在其他一些模块中:
在用法中上面,除了
define
和require
之外,没有其他内容是全局的。当然,这些只是说明性示例,因为在 RequireJS 中定义/使用模块有许多不同的风格。Loader example using RequireJS:
Define a utilities module in utils.js:
Use the above module in another module, say math.js:
And you can use math.js in another file, say main.js:
You can still have namespaces, and still keep them warm and cozy inside modules:
namespace.js:
Then the rest of the modules can use this namespace during definition:
Or at runtime, in some other module:
In the usages above, nothing but
define
andrequire
are global. Of course, these are just illustrative examples, as there are many different flavors of defining/using modules in RequireJS.