softsprint menu Заказать

ООП в прототипном стиле JavaScript

Январь 25, 2017 в 7:35 | wiki

Как мы знаем, в JavaScript есть два вида наследования:
— ООП в функциональном стиле;
— ООП в прототипном стиле;

Более популярным является прототипный стиль, поскольку имеет главное преимущество — методы в прототипе автоматически доступны везде и всегда. Почему? Методы записываются в объекте, ссылка на который находится в специальном свойстве prototype. Такое свойство есть у каждой функции — оно ссылается на объект с одним единственным свойством constructor:

1
2
3
4
function F() {};
F.prototype = {
  constructor: F
};

Объекты-прототипы есть и у встроенных конструкторов (Object.prototype, Array.prototype и т.д) — в них хранятся служебные методы, например, toString, join, прочие.
Мы также всегда можем добавить свои методы в объект конструктор, например:

1
2
Object.prototype.countSomething = function() {...}
F.prototype.countSomething = function() {...}

И эти методы станут доступны новым объекту, который создаст конструктор F:

1
2
3
4
function F() {};
F.prototype.countSomething = function() {...};
var f = new F();
f.countSomething(); // will work!

Каким образом?
Свойство F.prototype буквально означает, что при запуске конструктора F будет создан новый объект, который получит ссылку f.__proto__ на объект-прототип со всеми его методами:

object proto

Вот и получается, что:

1
2
3
alert(f.__proro__ == F.prototype) // true;
alert(f.countSomething == F.prototype.countSomething); // true
alert(f.__proro__. countSomething == F.prototype.countSomething); // true

Обратите внимание на последние 2 строки: если метод countSomething() не нашёлся в самом объекте f, созданным конструктором F, поиск продолжается в его объекте-прототипе (f.__proro__).

Пойдём дальше и рассмотрим наследование конструкторов один от другого. Пускай, у нас есть 2 конструктора: Second будет наследовать от First:

1
2
3
4
5
function First() {...};
First.prototype = {...}; // здесь общие методы в объекте-прототипе
function Second() {...};
Second.prototype = {...}; // здесь конкретные методы в объекте-прототипе
var obj = new Second();

Алгоритм наследования такой: если нужный метод не найдёт в объекте obj, мы ищем в Second.prototype (объекте-прототипе конструктора, который создал obj); если нужного метода и там нет, ищем в First.prototype:
obj > Second.prototype > First.prototype.

Как мы уже знаем, при создании новый объект obj автоматически получает ссылку на объект-прототип: obj.__proto__ == Second.prototype. А как же заставить Second.prototype наследовать от First.prototype?
Можно, конечно, прописать такую конструкцию: Second.prototype.__proto__ = First.prototype, но на самом деле есть специальный метод:

1
Second.prototype = Object.create(First.prototype);

Он создаёт новый пустой объект с ссылкой на объект-прототип First.prototype. Далее мы смело можем добавлять нужные нам методы в Second.prototype. Итоговая последовательность наследования:

1
2
3
4
5
6
function First() {...}; // объявили общий конструктор 
First.prototype = {...}; // добавили методы в его объект-прототип
function Second() {...}; // объявили конкретный конструктор
Second.prototype = Object.create(First.prototype); // создали пустой объект с ссылкой на прототип First.prototype
Second.prototype = {...}; // добавили методы в его объект-прототип
var obj = new Second(); // запустили конструктор

Давайте обсудим

softsprint heart

Наши контакты

Львов, Украина
mob: +380 97 551 44 55
skype: softsprint.net

Скажите Привет!