Javascript namespace pollution issue
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();
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.
Question 1: Is this correct? I want to add to the namespace from several separate .js files, so this way seems convenient.
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);
};
This was tested on Chrome 8 and I can't figure out how SomeObject
has come to have SomeFunc
as a member. This seems开发者_StackOverflow中文版 to be a hole in my limited knowledge of prototypes. Can someone explain?
let's start with the basics.
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.
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.
Question 2: is strange.
Here's what's happening:
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
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 is an object right?
Function.property === 5 // oh dear!
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.
Did I saw that dealing with .__proto__
was a bad idea? I think I should say it again.
In case your wondering this
was instance
, this.__proto__
was Object.prototype.SomeObject.prototype
and this.__proto__.__proto__
is Object.prototype
Here's a link to the garden Go read it.
Answer 2: SomeObject
has access to SomeFunc
in that way because this
refers to myNameSpaceProto
, and not SomeObject
.
Quirksmode has a decent explanation of why.
Here's a much better article explaining it.
So, as you might have guessed, Answer 1: Yes.
精彩评论