Skip to content

Instantly share code, notes, and snippets.

@zandroid
Created May 31, 2013 19:02
Show Gist options
  • Save zandroid/5687166 to your computer and use it in GitHub Desktop.
Save zandroid/5687166 to your computer and use it in GitHub Desktop.
function Rect(colot, width, height) {
// задаём поля, в будущем можем их изменить напрямую
this.color = color;
this.width = width;
this.height = height;
}
// [1.1] расширяем прототип:
// то же самое получим вызовом jQuery.extend(Rect.prototype, { ... });
Rect.prototype.s = function() {
// площадь
return this.width * this.height;
};
Rect.prototype.p = function() {
// периметр
return 2 * (this.width + this.height);
};
// [1.2] можно и так задать прототип, если класс не наследуеся от другого, так меньше писанины
// - почему нельзя, если наследуется? (= убьём наследование, объяснение ниже)
Rect.prototype = {
// т.к. создаём новый объект типа Object, то и конструктор у него будет Object
// поэтому требуется явно указать конструктор (вдруг он нам где-нибудь понадобится, например см. ниже)
constructor: Rect,
s: function() {
return this.width * this.height;
},
p: function() {
return 2 * (this.width + this.height);
}
};
function Square(color, width) {
// вызов базового конструктора
Rect.call(this, color, width, width); // or Rect.apply(this, [ color, width, width ]);
}
/* наследование:
Вообще парадигма прототипов сводится к тому, что у инстанса класса
есть скрытое* свойство __proto__ указывающее на Constructor.prototype,
и если какое-то поле или метод не найдены у инстанса, то происходит поиск
в прототипе, прототипе прототипа и т.д.
А наследование Squre от Rect в этом контексте означает, что
Square.__proto__.__proto__ => (Square.prototype.__proto__ =>) Rect.prototype,
т.е. прототип для Square должен быть "инстансом" Rect
*/
// [2.0] Просто скопировать все методы из протитпа базового класса в прототип наследника
// Не является наследованием, т.к. изменение потом прототипа базового класса никак не повлияет
// на класс наследика и не будет работать оператор instanceof ( sq instanceof Rect => false )
jQuery.extend(Square.prototype, Rect.prototype);
// [2.1] Плохой способ, т.к. отрабатывает конструктор базового класса
// и в прототип попадают поля, относящиеся к инстансу, но вполне годный, если писать
// конструктор базового класса определённым образом
// - каким образом надо написать конструктор базового класса Rect? (= если нет параметров, то сразу return)
Square.prototype = new Rect();
Square.prototype.constructor = Square; // вернули конструктор
// а дальше расширять прототип можно только с помощью явных присвоений или jQuery.extend, см. [1.1]
// [2.2] Хитрый способ, всякий уважающий себя JS-программер должен его знать, понимать и использовать
function F(){}; // создали пустой конструктор
F.prototype = Rect.prototype; // присвоили тот же самый прототип (по сути, просто заменили конструктор на пустой)
Square.prototype = new F(); // получили что и требовалось: Square.prototype.__proto__ => Rect.prototype
Square.prototype.constructor = Square; // вернули ссылку на родной конструктор
// [2.3] Новомодный способ (ECMAScript5), поддерживается IE9+, FF4+
Square.prototype = Object.create(Rect.prototype); // получили: Square.prototype.__proto__ => Rect.prototype
Square.prototype.constructor = Square; // вернули ссылку на родной конструктор
// - Зачем же мы везде возвращали ссылку на родной конструктор?
// = у инстанса можно определить локальное поле/метод, которое перекроет поле из конструктора,
// но к прототипу можно обратиться по имени функции конструктора или как раз через свойство .constructor
// и для этого не требуется иметь доступ к функции-конструктору
square1.s = function() {
console.log('trace calling of the square1 method "s"');
return this.constructor.prototype.s.apply(this, arguments);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment