开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜