В чем разница между объектом и прототипом в прототипном программировании?

Я пытаюсь понять «способ JavaScript» создания и использования объектов и думаю, что сталкиваюсь с непониманием объекта и прототипа.

В новом проекте, который я начал, я решил попробовать прототипное наследование. Я запутался, если это означает, что я должен просто создать объект, который я намереваюсь использовать, а затем создать другие объекты на основе этого, используя Object.create(), например:

var labrador = {
   color: 'golden',
   sheds: true,

   fetch: function()
   {
      // magic
   }
};

var jindo = Object.create(dog);
jindo.color = 'white';

Или, если я должен создать своего рода класс и создать его экземпляры, используя Object.create().

var Dog = { // Is this class-like thing a prototype?
   color: null,
   sheds: null,

   fetch: function()
   {
      // magic
   }
};

var labrador = Object.create(Dog);
labrador.color = 'golden';
labrador.sheds = true;

var jindo = Object.create(Dog);
jindo.color = 'white';
jindo.sheds = true;

Имея гораздо больший опыт в ООП на основе классов, последний метод кажется мне более удобным (и, возможно, этого достаточно). Но я чувствую, что дух прототипного наследования больше в первом варианте.

Какой метод больше соответствует «духу» прототипного программирования? Или я полностью упускаю суть?


person donut    schedule 26.09.2011    source источник


Ответы (2)


prototype — это просто еще один объект, на который объект имеет неявную ссылку.

Когда вы делаете:

var obj = Object.create( some_object );

... вы говорите, что хотите, чтобы obj пытался получить свойства от some_object, когда они не существуют на obj.

Таким образом, ваш второй пример будет ближе к тому, как вы его используете. Каждый объект, созданный с помощью Object.create(Dog), будет иметь в своей цепочке прототипов этот объект Dog. Поэтому, если вы внесете изменение в Dog, это изменение отразится на всех объектах, имеющих Dog в цепочке.

Если основной объект имеет то же свойство, что и объект-прототип, это свойство затеняет это свойство прототипа. Примером этого могут быть значения null, которые вы устанавливаете для свойств Dog.

Если вы сделаете:

var lab = Object.create(Dog);
lab.color = 'golden';

...теперь вы затеняете собственность color на Dog, так что вы больше не получите null. Вы не каким-либо образом меняете Dog, поэтому, если я создам еще один объект:

var colorless_dog = Object.create(Dog);

... этот по-прежнему будет получать значение null из цепочки прототипов при доступе к свойству color.

colorless_dog.color;  // null

... пока вы не затените его:

colorless_dog.color = 'blue';
colorless_dog.color;  // 'blue'

Итак, учитывая ваш пример:

var lab = Object.create(Dog);
lab.color = 'golden';
lab.sheds = true;

... это выглядит примерно так:

              // labrador              // Dog
lab.color---> color:'golden'           color:null
lab.sheds---> sheds:true               sheds:null

lab.fetch()--------------------------> fetch: function() {
                                          alert( this.color ); // 'golden'
                                          // "this" is a reference to the
                                          //    "lab" object, instead of "Dog"
                                       }
person user113716    schedule 26.09.2011
comment
Спасибо, это полезно. Кажется, что нет ничего противоречащего духу прототипного программирования в первом примере, но потенциально может быть сложно поддерживать его. - person donut; 26.09.2011
comment
@donut: Ну, в первом примере это зависит от того, что такое dog. Если вы хотели использовать labrador, а labrador имел dog в своей цепочке прототипов, а все labrador были color:'golden' и sheds:true, то да, имело бы смысл сделать это. Вы можете расширить цепочку прототипов на множество объектов, если это имеет смысл. Если fetch() должно применяться ко всем dog, то было бы более разумно иметь это на dog, чем на labrador. - person user113716; 26.09.2011

Прототип — это просто объект.

Это любой объект, который другой объект использует в качестве своего прототипа.

person timdev    schedule 26.09.2011
comment
Эти утверждения технически правильны. Однако они не помогают ответить на вопрос, поэтому -1 - person ; 26.09.2011
comment
@delnan - Думаю, так оно и есть. Других ответов не было, когда я давал свой. Мне не хватило времени для полноценного обсуждения, поэтому я представил центральную концепцию, необходимую для понимания темы. - person timdev; 26.09.2011