У каждого класса имеется один объект_прототип с одним наборов свойств, но по_ тенциально может существовать множество экземпляров класса, каждый из кото_ рых наследует свойства прототипа. Свойство прототипа может наследоваться мно_ гими объектами, поэтому интерпретатор JavaScript должен обеспечить фундамен_ тальную асимметричность между чтением и записью значений свойств. Когда вы читаете свойство p объекта o, JavaScript сначала проверяет, есть ли у объекта o свойство с именем p. Если такого свойства нет, то проверяется, есть ли свойство с именем p в объекте_прототипе. Так работает наследование на базе прототипов.
9.2. Прототипы и наследование
Однако когда свойству присваивается значение, JavaScript не использует объ_ ект_прототип. Чтобы понять почему, подумайте, что произошло бы в этом слу_ чае: предположим, вы пытаетесь установить значение свойства o.p, а у объекта o нет свойства с именем p. Предположим теперь, что JavaScript идет дальше и ищет свойство p в объекте_прототипе объекта o и позволяет вам изменить зна_ чение свойства прототипа. В результате вы изменяете значение p для всего клас_ са объектов, а это вовсе не то, что требовалось.
Поэтому наследование свойств происходит только при чтении значений свойств, но не при их записи. Если вы устанавливаете свойство p в объекте o, который на_ следует это свойство от своего прототипа, происходит создание нового свойства непосредственно в объекте p. Теперь, когда объект o имеет собственное свойство с именем p, он больше не наследует значение p от прототипа. Когда вы читаете значение p, JavaScript сначала ищет его в свойствах объекта o. Так как он нахо_ дит свойство p, определенное в o, ему не требуется искать его в объекте_прототи_ пе, и JavaScript никогда не будет искать определенное в нем значение p. Мы ино_ гда говорим, что свойство p «затеняет» (скрывает) свойство p объекта_прототипа. Наследование прототипов может показаться запутанным, но все вышеизложен_ ное хорошо иллюстрирует рис. 9.1.
Рис. 9.1. Объекты и прототипы
170 Глава 9. Классы, конструкторы и прототипы
Свойства прототипа совместно используются всеми объектами класса, поэтому, как правило, их имеет смысл применять только для определения свойств, совпа_ дающих для всех объектов класса. Это делает прототипы идеальными для опре_ деления методов. Другие свойства с постоянными значениями (такими как ма_ тематические константы) также подходят для определения в качестве свойств прототипа. Если класс определяет свойство с очень часто используемым значе_ нием по умолчанию, то можно определить это свойство и его значение по умол_ чанию в объекте_прототипе. Тогда те немногие объекты, которые хотят изме_ нить значение по умолчанию, могут создавать свои частные копии свойства и оп_ ределять собственные значения, отличные от значения по умолчанию.