Я только начинаю работать с 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. Кажется, это пробел в моих ограниченных знаниях о прототипах. Может кто-нибудь объяснить?
Ответ 1 · рейтинг 10 · Raynos
давайте начнем с основ.
Не трогайте __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. Таким образом, этот метод определен для КАЖДОГО объекта. Включая .__proto__, потому что это тоже объект.
Видел ли я, что иметь дело с .__proto__ было плохой идеей? Я думаю, я должен сказать это снова.
Если вам интересно, this было instance, this.__proto__ было Object.prototype.SomeObject.prototype, а this.__proto__.__proto__ было Object.prototype
Вот ссылка на garden Прочтите.
Ответ 2 · рейтинг -1 · sdleihssirhc
Ответ 2: SomeObject имеет доступ к SomeFunc таким образом, потому что this относится к myNameSpaceProto, а не SomeObject.
Quirksmode дает достойное объяснение, почему это так.
Вот гораздо лучшая статья, объясняющая это.
Итак, как вы могли догадаться, Ответ 1: Да.