JavaScript名称空间污染问题 [英] Javascript namespace pollution issue
问题描述
我只是接触Javascript,所以我对命名空间的第一次尝试最终看起来像这样:
I'm just getting in to Javascript, so my first attempt at namespaces ended up looking like this:
var myNameSpace = {};
var myNameSpaceProto = myNameSpace.__proto__;
myNameSpaceProto.SomeFunc = function()
{
alert("SomeFunc()");
};
myNameSpaceProto.SomeObject = function()
{
alert("SomeObject constructor");
};
var instance = new myNameSpace.SomeObject();
我认为我可以放心地跳过原型步骤,而只需使用myNameSpace.SomeFunc = function...
,因为只有一个myNameSpace
对象实例,因此原型不会保存任何内容.
I gather I can safely skip the prototype step and simply have myNameSpace.SomeFunc = function...
, because there's only ever one myNameSpace
object instance so the prototype doesn't save anything.
问题1:这是正确的吗?我想从几个单独的.js文件添加到名称空间,所以这种方式似乎很方便.
Question 1: Is this correct? I want to add to the namespace from several separate .js files, so this way seems convenient.
问题2:通过上面的代码片段,我发现了名称空间污染的怪异副作用,如以下SomeObject
正文所示:
Question 2: With the above code snippet I found a weird side-effect of namespace pollution, which is shown by the following SomeObject
body:
myNameSpaceProto.SomeObject = function()
{
// As expected NonexistantFunc is not a member of this and returns "undefined"
alert("typeof this.NonexistantFunc = " + typeof this.NonexistantFunc);
// Returns 'function'. How has SomeFunc made it to this.SomeFunc? It's supposed to be under myNameSpace.SomeFunc
alert("typeof this.SomeFunc = " + typeof this.SomeFunc);
// Turns out it's in the prototype's prototype. Why?
alert("this.__proto__.__proto__.SomeFunc = " + this.__proto__.__proto__.SomeFunc);
};
这已在Chrome 8上进行了测试,我不知道SomeObject
如何成为SomeFunc
的成员.在我对原型的有限了解中,这似乎是一个漏洞.有人可以解释吗?
This was tested on Chrome 8 and I can't figure out how SomeObject
has come to have SomeFunc
as a member. This seems to be a hole in my limited knowledge of prototypes. Can someone explain?
推荐答案
让我们从基础开始.
请勿触摸__proto__
.这是潘多拉的盒子.你不想惹那个.不仅不支持跨浏览器,而且您可以编写一些丑陋的代码,而无需使用它.
Don't touch __proto__
. It's a pandora's box. You do not want to mess with that. Not only is it not supported cross-browser but you can write some hideous code and there's no need to use it.
var Constructor = new Function;
Constructor.fn = Constructor.prototype;
Constructor.fn.someFunc = function() {
alert("someFunc");
}
var obj = new Constructor;
var namespace = {};
namespace.someStaticFunc = function() {
alert("someStaticFunc");
}
您需要区分名称空间和构造函数.有什么真正的理由为什么需要将命名空间的方法写入原型而不是对象的属性?
You need to distinquish between a namespace and a constructor. Is there any real reason why the methods of the namespace needs to be written to the prototype rather then as properties of the object?
因此,要回答一个问题,您可以跳过原型.
So for answer one yes you can skip the prototype.
关于第二个问题,因为您最初实际编写原型时要执行的操作是直接在对象上编辑方法.
As for question two since your writing to the prototype originally what you actaully are doing is editing the methods on the object directly.
将.prototype
视为Class
定义.如果编辑obj.__proto__
,则在运行时编辑Object
的Class
.您破坏了从该Class
派生的所有其他对象.动态类很好.但是从对象内部编辑类是创建晦涩的bug的好方法.
Consider .prototype
to be the Class
definition. If your editing obj.__proto__
your editing the Class
of the Object
at run-time. Your corrupting all the other Objects derived from that Class
. Dynamic classes are fine. But editing classes from within objects is a really good way to create obscure bugs.
问题2:很奇怪.
正在发生的事情:
var o = {}; // Ok o is an object
var o.__proto__.property = 5; // Ok I changed o's class and it now has a property = 5.
var o.__proto__.construct = function() { }; // Ok I changed the class again it now has a constructor
var p = new o.construct(); // we create an object from my constructor.
(p.__proto__ === o.construct.prototype) // true! the proto object is o.c.prototype. Because
// p is created from o.c so the prototype is that of o.c
(o.construct.__proto__ === Object.prototype) // true! Oh-uh. Now look what we've been doing!
// When you created `var o = {}` and edited o.__proto__ you've been editing Object.prototype
您看到闹钟了吗?您一直在动态编辑Object类.您周围的所有代码都崩溃了.
Do you see the alarm bells yet? You've been editing the Object class on the fly. All your code around you is falling apart.
函数是对象吗?
Function.property === 5 // oh dear!
我们找到了全部原因.我们一直在将这些方法写入Object.prototype.因此,每个对象都在其上定义了该方法.包括.__proto__
也是因为它也是一个对象.
We found the entire cause. We've been writing those methods to Object.prototype. So EVERY object has that method defined on it. Including .__proto__
because that's an object too.
我看到与.__proto__
打交道是一个坏主意吗?我想我应该再说一遍.
Did I saw that dealing with .__proto__
was a bad idea? I think I should say it again.
如果您想知道的this
是instance
,this.__proto__
是Object.prototype.SomeObject.prototype
而this.__proto__.__proto__
是Object.prototype
In case your wondering this
was instance
, this.__proto__
was Object.prototype.SomeObject.prototype
and this.__proto__.__proto__
is Object.prototype
这里是花园的链接.
这篇关于JavaScript名称空间污染问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!