Проблема загрязнения пространства имен Javascript - PullRequest
0 голосов
/ 28 января 2011

Я только вхожу в Javascript, поэтому моя первая попытка использования пространств имен в итоге выглядела так:

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 экземпляр объекта, поэтому прототип ничего не сохраняет.

Вопрос 1: Это правильно?Я хочу добавить в пространство имен несколько отдельных файлов .js, поэтому этот способ кажется удобным.

Вопрос 2: С помощью приведенного выше фрагмента кода я обнаружил странный побочный эффект загрязнения пространства имен, что показано следующим SomeObject телом:

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 в качестве члена.Кажется, это дыра в моих ограниченных знаниях о прототипах.Может кто-нибудь объяснить?

Ответы [ 2 ]

10 голосов
/ 28 января 2011

Давайте начнем с основ.

Не трогай __proto__. Это ящик Пандоры. Вы не хотите возиться с этим. Мало того, что он не поддерживается кросс-браузер, но вы можете написать отвратительный код, и нет необходимости использовать его.

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");
}    

Вам нужно различать пространство имен и конструктор. Есть ли реальная причина, по которой методы пространства имен должны записываться в прототип, а не в качестве свойств объекта?

Так что для ответа один да, вы можете пропустить прототип.

Что касается второго вопроса, так как изначально вы пишете прототипу то, что вы делаете, то редактируете методы непосредственно для объекта.

Рассмотрим .prototype как определение Class. Если вы редактировали obj.__proto__, вы редактировали Class из Object во время выполнения. Вы испортили все другие объекты, полученные из этого Class. Динамические классы в порядке. Но редактирование классов внутри объектов - это действительно хороший способ создания скрытых ошибок.

Вопрос 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 на лету. Весь ваш код вокруг вас разваливается.

Функция - это объект, верно?

Function.property === 5 // oh dear!

Мы нашли всю причину. Мы писали эти методы в Object.prototype. Таким образом, EVERY объект имеет этот метод, определенный на нем. Включая .__proto__, потому что это тоже объект.

Видел ли я, что иметь дело с .__proto__ было плохой идеей? Я думаю, что я должен сказать это снова.

В случае, если ваше удивление this было instance, this.__proto__ было Object.prototype.SomeObject.prototype и this.__proto__.__proto__ было Object.prototype

Вот ссылка на сад Иди и прочитай.

0 голосов
/ 28 января 2011

Ответ 2: SomeObject имеет доступ к SomeFunc таким образом, потому что this относится к myNameSpaceProto, а не SomeObject.

Quirksmode имеет достойное объяснение того, почему.

Вот гораздо лучшая статья, объясняющая это.Как вы уже догадались, Ответ 1: Да.

...