#javascript #prototype
#javascript #прототип
Вопрос:
Я не понимаю, почему происходит следующее:
function Class() {}
Class.prototype.foo = {a: 1};
Class.prototype.bar = 1;
x = new Class();
y = new Class();
y.foo.a = 2;
y.bar = 2;
x.foo.a; //2
x.bar; //1
Когда я устанавливаю y.foo.a
значение 2, кажется, что он выполняет ту же операцию, что и y.constructor.prototype.foo.a = 2
. Почему это должно быть, учитывая, что это y.bar = 2
не влияет y.constructor.prototype.bar
?
Ответ №1:
Вы смешиваете свойства прототипа со свойствами, которые являются локальными для экземпляра объекта. Используя y.bar = 2
, вы присваиваете свойство экземпляра ( bar
) экземпляру y
. При интерпретации свойство ( bar
) сначала просматривается внутри самого экземпляра. Если он там не найден, поиск продолжается в экземплярах prototype. Теперь вы присвоили bar
значение y
so y.bar = 2
, но экземпляр x
не знает об этом, поэтому для x
поиска продолжает использовать свой прототип (то есть prototype.bar
, по-прежнему со значением 1).
Для y.foo.a
foo
в y
нет свойства экземпляра, поэтому оно просматривается в его прототипе. Там оно найдено, и свойству a
присваивается новое значение. Поскольку вы тем самым изменяете значение Class.prototype
свойства foo
, оно также представлено в x
.
Если вы хотите изменить bar в его прототипе (таким образом, исходящем из экземпляра y
), вам придется использовать прототип y
‘s constructor
(который является Class
):
y.constructor.prototype.bar = 2;
Может, мистер Дуглас Крокфорд сможет прояснить для вас ситуацию (перейдите примерно к 23-й минуте видео о наследовании прототипов)?
Ответ №2:
Вы читаете, y.foo
но присваиваете y.bar
. Это разные операции с разной семантикой. Параметр y.foo.bar
должен сначала быть прочитан y.foo
: он ищет значение foo
в y
, не может его найти, затем заглядывает в y
прототип, обнаруживает объект и только после этого изменяет этот объект. присвоение y.bar просто ищет y, а затем изменяет его. x.bar
и y.bar
затем обозначают разные объекты, в то время как x.foo
и и y.foo
обозначают один и тот же объект.
Ответ №3:
При чтении атрибута выполняется поиск в объекте-прототипе, если он не определен в основном объекте.
Установка атрибута всегда устанавливает его для основного объекта и НИКОГДА для объекта-прототипа.
Из-за этого всегда бывает плохой идеей определять что-то другое, кроме функций или значений, которые никогда не изменятся в объектах-прототипах.
Чтобы действительно понять, что происходит, я рекомендую вам поэкспериментировать с
__proto__
атрибут. Я знаю, не все браузеры поддерживают это, но это действительно помогает вам понять, как работает прототипирование в JavaScript.