SlideShare a Scribd company logo
JavaScript. OOP (in russian)
Михаил Давыдов
Разработчик JavaScript
JavaScript ООП
3
JavaScript ООП
•  Нет классов
–  Но можно эмулировать их
•  Есть прототипы
•  Есть наследование на прототипах
–  Делегирующее прототипное наследование
•  Все можно менять во время работы
–  Цепочку наследования можно менять
–  Прототипы можно менять
–  На классах так сделать нельзя
•  Можно изменить прототипы базовых
"классов"
4
Сказка о мутантах
5
Сказка о мутантах
•  В далекой-далекой галактике
•  Нет привычного нам наследования
•  Есть телепатическое наследование
–  "Телегенез"
•  Действующие лица:
–  Дедушка
–  Отец
–  Сын
6
Структура мутанта
Мутант	

"Телепатические"	

гены	

Собственные	

гены	

Движение генов
7
Все зеленые
Color	
  
Дед	

 Отец	

 Сын
8
Дед: хочу стать синим!
Color	
  
Дед	

 Отец	

 Сын
9
Все посинели
Color	
  
Дед	

 Отец	

 Сын
10
Отец: верну-ка я цвет
Color	
   Color	
  
Дед	

 Отец	

 Сын
11
Дед синий, отец и сын зеленые
Color	
   Color	
  
Дед	

 Отец	

 Сын
12
Сын: хочу быть черным
Color	
  
Color	
   Color	
  
Дед	

 Отец	

 Сын
13
Мутанты и JavaScript
Size,	
  
Age	
  
Color	
  
Объект	

Свойства 	

прототипа	

Собственные	

свойства	

Делегирование	

Цепочка прототипов
14
Собственные свойства и прототип
•  Собственные свойства
•  Свойства прототипа
•  Любой объект имеет ссылку на прототип
–  И примитив также*
–  Имеет с рождения
–  По умолчанию – Object.prototype
•  Делегирование
–  Мы можем пользоваться функциями прототипа не имея собственных
•  Цепочка прототипов
–  Каждый прототип это тот же объект
–  Который также может иметь прототип
–  У прототипа прототипа также может быть прототип
Вызывает функцию как конструктор
Строит цепочку прототипов
Оператор new
16
Работа оператора new
•  new(Constructor, arguments):*!
•  Получает на вход 2 операнда
–  Функция должна иметь свойство prototype
•  Создает временный объект (obj)
•  Добавляет свойство __proto__
–  obj.__proto__ = Constructor.prototype
•  Вызывает конструктор над объектом
–  Constructor.apply(obj, arguments)
•  Конструктор вернул примитив. Результат obj
•  Иначе то, что вернул конструктор
17
new Smth() может вернуть
не инстанс Smth!
18
function Constructor() {
// no body
}
new Constructor() instanceof Constructor === true; // OK
// Подмена результата
function Constructor () {
return {}; // <<<
}
new Constructor() instanceof Constructor === false; // <<<
// Аналогично
function Constructor() {return []}
function Constructor() {return function () {}}
Подмена инстанса
19
It isn't JavaScript bug, it is feature!
20
function myNew(Constructor, args) {
if (typeof Constructor !== "function") {
throw new TypeError();
}
if (typeof Constructor.prototype === "undefined") {
throw new TypeError();
}
var obj = {
__proto__: Constructor.prototype
};
var result = Constructor.apply(obj, args);
if (typeof result === "object" && result !== null ||
typeof result === "function") {
return result;
}
return obj;
}
Оператор new в коде
21
Во многих браузерах
__proto__ скрытое свойство.
Менять и получать нельзя!
22
// Конструктор Grandfather
var Grandfather = function () {};
Grandfather.prototype.color = 'green';
Пример new
var gf = new Grandfather();
gf.color; // "green"
// Это аналогично
var gf = {
__proto__: Grandfather.prototype
};
gf.color; // "green"
23
Оператор new используется
для построения цепочек
прототипов
Цепочка прототипов
это способ наследования в JavaScript
25
Цепочка прототипов
// Конструктор Grandfather
var Grandfather = function () {};
Grandfather.prototype.color = 'green';
// Конструктор Father
var Father = function () {};
typeof Father.prototype === "object";
// Для цепочки нам нужно получить вот это
Father.prototype = {
__proto__: Grandfather.prototype
};
26
Строим цепочку прототипов явно
// Конструктор Father
var Father = function () {};
Father.prototype = new Grandfather();
// Как помним, это аналогично:
Father.prototype = {
__proto__: Grandfather.prototype
};
27
Не забываем! __proto__
лучше установить явно –
через оператор new
28
var Grandfather = function () {}; // Конструктор Grandfather
Grandfather.prototype.color = 'green';
var Father = function () {}; // Конструктор Father
Father.prototype = new Grandfather(); // Наследуем
var Son = function () {}; // Конструктор Son
Son.prototype = new Father(); // Наследуем
var g = new Grandfather(); // Экземпляр "класса" Grandfather
var f = new Father(); // Экземпляр "класса" Father
var s = new Son(); // Экземпляр "класса" Son
// Изначально все зеленые
console.log([g.color, f.color, s.color]);
// ["green", "green", "green"]
Пример с мутантами
29
// Дед решил поменять свой цвет и цвет потомства
Grandfather.prototype.color = 'blue';
// Все синие
console.log([g.color, f.color, s.color]);
// ["blue", "blue", "blue"]
// Отец решил все вернуть для себя и своего потомства
Father.prototype.color = 'green';
// Хотя мог исделать и так:
// Grandfather.prototype.color = 'green';
// Цвет вернулся
console.log([g.color, f.color, s.color]);
// ["blue", "green", "green"]
Пример с мутантами
30
// Смысла нет
Grandfather.prototype.color = 'blue';
console.log([g.color, f.color, s.color]);
// ["blue", "green", "green"]
// Сын решил поменял только собственное свойство
s.color = 'black';
console.log([g.color, f.color, s.color]);
// ["blue", "green", "black"]
var SonsSon = function () {}; // Конструктор SonsSon
SonsSon.prototype = new Son(); // Наследуем
var ss = new SonsSon(); // Экземпляр "класса" SonsSon
console.log([g.color, f.color, s.color, ss.color]);
// ["blue", "green", "black", "green"]
Пример с мутантами
31
Цепочка прототипов: Grandfather
g
__proto__ object
Grandfather.prototype
color blue
__proto__ object
Object.prototype
__proto__ null
32
В конце экземпляр Son будет таким. Hell Mess…
var s = {
color: 'black', // Поменял только собственное свойство
__proto__: { // Son.prototype
__proto__: { // Father.prototype
color: 'green', // Отец решил вернуть цвет
__proto__: { // Grandfather.prototype
color: 'blue', // Дед решил поменять цвет
__proto__: { // Object.prototype
// Много разных свойств
__proto__: null
}
}
}
}
};
Цепочка прототипов: Son
33
34
А что, если в конструкторе
alert(), а если он добавляет
свойства?
35
alert('Mua-ha-ha')
// Конструктор Grandfather
var Grandfather = function () {
alert('Mua-ha-ha');
return ["Mua-ha-ha!"];
};
Grandfather.prototype.color = 'green';
// Конструктор Father
var Father = function () {};
Father.prototype = new Grandfather();
36
alert('Mua-ha-ha')
// Конструктор Grandfather
var Grandfather = function () {
alert('Mua-ha-ha');
return "Mua-ha-ha!";
};
Grandfather.prototype.color = 'green';
// Конструктор Father
var Father = function () {};
Father.prototype = new Grandfather();
37
Используется для чистого наследования цепочки прототипов
new – это просто средство подмешать prototype
function inherits(Constructor, SuperConstructor) {
var F = function () {}; // Временный, чистый конструктор
// Сохраняем ссылку
F.prototype = SuperConstructor.prototype;
// Применяем __proto__ = prototype
Constructor.prototype = new F();
}
Функция inherits или подобная
var Grandfather = function () {}; // Конструктор Grandfather
Grandfather.prototype.color = 'green';
var Father = function () {}; // Конструктор Father
// Father.prototype = new Grandfather();
inherits(Father, Grandfather); // Наследуем
38
Есть еще один вариант использовать Object.create();
Только ECMAScript 5
var Grandfather = function () {}; // Конструктор Grandfather
Grandfather.prototype.color = 'green';
var Father = function () {}; // Конструктор Father
// Father.prototype = new Grandfather();
// Что она делает - понятно
Father.prototype = Object.create(Grandfather.prototype);
// Полная и абсолютно честная версия
Father.prototype = Object.create(Grandfather.prototype, {
constructor: {
value: Father,
enumerable: false,
writable: true,
configurable: true
}
});
ECMAScript 5 – Object.create()
Оператор "точка" и []
Получение свойств
Используют цепочку
прототипов и
собственные свойства
41
Оператор "точка" и []
•  getProperty(obj, name): *!
•  Ищет в собственных свойствах
•  Нет? – ищем в цепочке прототипов
•  Пока __proto__ !== null
•  Не нашли – возвращаем undefined
42
function getProperty(obj, name) {
// Ищем в собственных
if (obj.hasOwnProperty(name)) {
return obj[name];
}
// Ищем рекурсивно в цепочке прототипов
else if (obj.__proto__ !== null) {
return getProperty(obj.__proto__, name);
}
// Не нашли
else {
return undefined;
}
}
// Пример
getProperty(s, "color") === s.color;
Оператор "точка" и [] в коде
43
Цепочка прототипов объекта s
s
color black
__proto__ object
Son.prototype
__proto__ object
Grandfather.prototype
color blue
__proto__ object
Object.prototype
__proto__ null
Участок цепочки Father пропущен
44
Храните функции в
прототипе, а данные в
собственных свойствах
Оператор instanceof
46
var u = new Grandfather();
var f = new Father();
var s = new Son();
s instanceof Son === true; // OK
s instanceof Father === true; // OK?
s instanceof Grandfather === true; // OK??
// Неужели множественное наследование???
s instanceof Object === true; // WAT???
s instanceof Array === false; // ОК!
Оператор instanceof
47
Оператор instanceof
использует цепочку
прототипов
48
Оператор instanceof
•  instanceof(obj, Constructor):Boolean!
•  Использует цепочку прототипов
•  Рекурсивно проверяет равенство
Constructor.prototype === obj.__proto__!
•  До того пока __proto__ !== null – вернет false
49
function isInstanceOf(obj, Сonstructor) {
// Нашли
if (obj.__proto__ === Сonstructor.prototype) {
return true;
}
// Ищем дальше рекурсивно
else if (obj.__proto__ !== null) {
return isInstanceOf(obj.__proto__, Сonstructor);
}
// Не нашли
else {
return false;
}
}
// Пример
isInstanceOf(s, Father) === s instanceof Father;
Оператор instanceof в коде
50
Цепочка прототипов объекта s
s
color black
__proto__ object
Son.prototype
__proto__ object
Grandfather.prototype
color blue
__proto__ object
Object.prototype
__proto__ null
Участок цепочки Father пропущен
51
var s = new Son();
s instanceof Array === false; // ОК!
Grandfather.prototype.__proto__ =
Array.prototype;
s instanceof Array === true; // WAT???
Оператор instanceof
52
var s = new Son();
s instanceof Array === false; // ОК!
Grandfather.prototype.__proto__ =
Array.prototype;
s instanceof Array === true; // WAT???
Оператор instanceof
Вызов конструктора родителя
Вызов метода родителя
Вызов метода родителя
54
var Grandfather = function (name) {
this.name;
};
Grandfather.prototype.hello = function () {
return 'I am ' + this.name;
};
var Father = function (name) {
Grandfather.call(this, name);
};
Father.prototype.hello = function () {
return Grandfather.prototype.hello.call(this)
+ ' – Father';
};
Вызов метода родителя
Классы?
ECMAScript 6 class
Библиотеки для эмуляции классов
Трансляция в JavaScript
56
Находится в стадии черновика спецификации
class Grandfather {
constructor () {}
public color 'blue';
}
class Father extends Grandfather {
constructor () {}
public color 'green';
}
var f = new Father();
ECMAScript 6 class
JavaScript. OOP (in russian)
58
В JavaScript нет и не будет
классов. Слово class –
синтаксический сахар.
59
Все это в конечном итоге будет цепочкой
прототипов. Вот такой:
var Grandfather = function () {}; // Конструктор Grandfather
Grandfather.prototype.color = 'blue';
var Father = function () {}; // Конструктор Father
Father.prototype = Object.create(Grandfather.prototype);
Father.prototype.color = 'green';
ECMAScript 6 class
Есть несколько библиотек…
Библиотеки для классов
61
Таких библиотек over 9000
62
Каждый программист на
JavaScript должен написать
свою реализацию классов ©
63
Библиотеки для классов
•  Mootools
•  Klass
•  JSClas
•  …
Over 9000 http://habrahabr.ru/post/132698/#comment_4404597
64
Mootools
var Grandfather = new Class({
initialize: function () {
}
});
var Father = new Class({
Extends: Grandfather,
initialize: function () {
}
});
Все они выглядят примерно так
65
В JavaScript нет и не будет
классов. new Class – для
удобства разработчика.
Пишем на одном языке, где есть
классы, а затем переделываем в
JavaScript!
Трансляция в JS
67
Много языков транслируется в JS
•  CoffeeScript
•  Dart
•  TypeScript
•  Processing
•  Python, Delphi, Ruby, C++ (LLVM)
68
Зачем транслируют?
•  Не знают JavaScript и его особенностей
•  Удобно писать на 1м языке
–  Python, Ruby
•  Синтаксический сахар
–  CoffeeScript, Dart, TypeScript
•  Очень долго переписывать
–  Программы на C++
69
Проблемы трансляции
•  Может быть крайне не оптимальна
–  Тормоза и лаги
–  Много костылей
•  На выходе плохо читаемый код
–  Сделан роботами для роботов
•  Отлаживать в любом случае JavaScript
70
Лучше применять
трансляцию в JavaScript
только в крайнем случае!
Изменение базовых классов
Да, их также можно менять!
String.prototype
Array.prototype
Number.prototype
…
72
// Чтобы не зацепить хорошие браузеры
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement) {
for (var i = 0; i < this.length; i++) {
if (this[i] === searchElement) {
return i;
}
}
return -1;
};
}
[1, 2, 3, 4].indexOf(3); // 2
Polyfill для Array#indexOf
Внимание! Это не полная реализация – не используйте ее!
Все, что влезло в слайд.
Array indexOf method http://clck.ru/3mm5x
73
Number.prototype.times = function (callback) {
for (var i = 0; i < this; i++) {
callback(i);
}
};
// Пример
(10).times(function (index) {
console.log(index);
});
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
Number#times
74
Прототипы базовых классов
изменяем только в крайнем
случае или для polyfill!
75
JavaScript ООП
•  Нет классов – есть прототипы
•  Прототипное наследование
•  Цепочка прототипов
–  inherits, Object.create()
•  __proto__ и prototype
•  Оператор new
•  Оператор instanceof
•  Оператор точка и []
•  Много библиотек для классов
•  Трансляция в JavaScript – крайний случай
Основы и заблуждения насчет JavaScript
http://clck.ru/0zjHr
77
Михаил Давыдов
Разработчик JavaScript
azproduction@yandex-team.ru
azproduction
Спасибо

More Related Content

PDF
new JavaScript
PPT
бегун
PPT
Groovy On Grails
PDF
Present saint-per3-by-pavel-vlasov
PPTX
Ruby - или зачем мне еще один язык программирования?
PDF
Почему Mojolicious?
PDF
Decorators' recipes
PPT
бегун
new JavaScript
бегун
Groovy On Grails
Present saint-per3-by-pavel-vlasov
Ruby - или зачем мне еще один язык программирования?
Почему Mojolicious?
Decorators' recipes
бегун

Viewers also liked (11)

PDF
JavaScript. Event Loop and Timers (in russian)
PDF
Ajax and Transports (in russian)
PDF
Dart - светлая сторона силы?
PDF
Dump-IT Загрузка и инициализация JavaScript
PDF
JavaScript. Basics (in russian)
PDF
JavaScript. Loops and functions (in russian)
PDF
Components now! (in russian)
PDF
Introduction in Node.js (in russian)
PDF
JavaScript. Event Model (in russian)
PDF
JavaScript. Async (in Russian)
PDF
Components now!
JavaScript. Event Loop and Timers (in russian)
Ajax and Transports (in russian)
Dart - светлая сторона силы?
Dump-IT Загрузка и инициализация JavaScript
JavaScript. Basics (in russian)
JavaScript. Loops and functions (in russian)
Components now! (in russian)
Introduction in Node.js (in russian)
JavaScript. Event Model (in russian)
JavaScript. Async (in Russian)
Components now!
Ad

Similar to JavaScript. OOP (in russian) (19)

PDF
Михаил Давыдов: JavaScript. Базовые знания
PDF
Очень вкусный фрукт Guava
PPT
ООП в JavaScript
PDF
JavaScript не нужен, CoffeeScript - мимими
PPTX
Зачем нужна Scala?
PPTX
Funny JS #2
PDF
Артем Яворский "@babel/core": "7.x"
PDF
Михаил Давыдов — JavaScript: Базовые знания
PDF
O Babel 7 и немного больше, Артем Яворский
PPTX
Поговорим о JavaScript, основы и современные тенденции развития языка
PDF
Groovy presentation.
PDF
Михаил Давыдов - JavaScript. Базовые знания
PDF
Михаил Давыдов - Транспорт, ajax
PPTX
JavaScript: хороший тон клиентской разработки
PDF
Plugin for plugin, or extending android new build system
PDF
TypeScript: особенности разработки / Александр Майоров (Tutu.ru)
PDF
Groovy jug-moscow-part 1
PDF
Объектное и прототипное программирование в Javascript
PDF
модульное тестирование для Perl. алексей шруб. зал 4
Михаил Давыдов: JavaScript. Базовые знания
Очень вкусный фрукт Guava
ООП в JavaScript
JavaScript не нужен, CoffeeScript - мимими
Зачем нужна Scala?
Funny JS #2
Артем Яворский "@babel/core": "7.x"
Михаил Давыдов — JavaScript: Базовые знания
O Babel 7 и немного больше, Артем Яворский
Поговорим о JavaScript, основы и современные тенденции развития языка
Groovy presentation.
Михаил Давыдов - JavaScript. Базовые знания
Михаил Давыдов - Транспорт, ajax
JavaScript: хороший тон клиентской разработки
Plugin for plugin, or extending android new build system
TypeScript: особенности разработки / Александр Майоров (Tutu.ru)
Groovy jug-moscow-part 1
Объектное и прототипное программирование в Javascript
модульное тестирование для Perl. алексей шруб. зал 4
Ad

JavaScript. OOP (in russian)

  • 3. 3 JavaScript ООП •  Нет классов –  Но можно эмулировать их •  Есть прототипы •  Есть наследование на прототипах –  Делегирующее прототипное наследование •  Все можно менять во время работы –  Цепочку наследования можно менять –  Прототипы можно менять –  На классах так сделать нельзя •  Можно изменить прототипы базовых "классов"
  • 5. 5 Сказка о мутантах •  В далекой-далекой галактике •  Нет привычного нам наследования •  Есть телепатическое наследование –  "Телегенез" •  Действующие лица: –  Дедушка –  Отец –  Сын
  • 8. 8 Дед: хочу стать синим! Color   Дед Отец Сын
  • 10. 10 Отец: верну-ка я цвет Color   Color   Дед Отец Сын
  • 11. 11 Дед синий, отец и сын зеленые Color   Color   Дед Отец Сын
  • 12. 12 Сын: хочу быть черным Color   Color   Color   Дед Отец Сын
  • 13. 13 Мутанты и JavaScript Size,   Age   Color   Объект Свойства прототипа Собственные свойства Делегирование Цепочка прототипов
  • 14. 14 Собственные свойства и прототип •  Собственные свойства •  Свойства прототипа •  Любой объект имеет ссылку на прототип –  И примитив также* –  Имеет с рождения –  По умолчанию – Object.prototype •  Делегирование –  Мы можем пользоваться функциями прототипа не имея собственных •  Цепочка прототипов –  Каждый прототип это тот же объект –  Который также может иметь прототип –  У прототипа прототипа также может быть прототип
  • 15. Вызывает функцию как конструктор Строит цепочку прототипов Оператор new
  • 16. 16 Работа оператора new •  new(Constructor, arguments):*! •  Получает на вход 2 операнда –  Функция должна иметь свойство prototype •  Создает временный объект (obj) •  Добавляет свойство __proto__ –  obj.__proto__ = Constructor.prototype •  Вызывает конструктор над объектом –  Constructor.apply(obj, arguments) •  Конструктор вернул примитив. Результат obj •  Иначе то, что вернул конструктор
  • 17. 17 new Smth() может вернуть не инстанс Smth!
  • 18. 18 function Constructor() { // no body } new Constructor() instanceof Constructor === true; // OK // Подмена результата function Constructor () { return {}; // <<< } new Constructor() instanceof Constructor === false; // <<< // Аналогично function Constructor() {return []} function Constructor() {return function () {}} Подмена инстанса
  • 19. 19 It isn't JavaScript bug, it is feature!
  • 20. 20 function myNew(Constructor, args) { if (typeof Constructor !== "function") { throw new TypeError(); } if (typeof Constructor.prototype === "undefined") { throw new TypeError(); } var obj = { __proto__: Constructor.prototype }; var result = Constructor.apply(obj, args); if (typeof result === "object" && result !== null || typeof result === "function") { return result; } return obj; } Оператор new в коде
  • 21. 21 Во многих браузерах __proto__ скрытое свойство. Менять и получать нельзя!
  • 22. 22 // Конструктор Grandfather var Grandfather = function () {}; Grandfather.prototype.color = 'green'; Пример new var gf = new Grandfather(); gf.color; // "green" // Это аналогично var gf = { __proto__: Grandfather.prototype }; gf.color; // "green"
  • 23. 23 Оператор new используется для построения цепочек прототипов
  • 24. Цепочка прототипов это способ наследования в JavaScript
  • 25. 25 Цепочка прототипов // Конструктор Grandfather var Grandfather = function () {}; Grandfather.prototype.color = 'green'; // Конструктор Father var Father = function () {}; typeof Father.prototype === "object"; // Для цепочки нам нужно получить вот это Father.prototype = { __proto__: Grandfather.prototype };
  • 26. 26 Строим цепочку прототипов явно // Конструктор Father var Father = function () {}; Father.prototype = new Grandfather(); // Как помним, это аналогично: Father.prototype = { __proto__: Grandfather.prototype };
  • 27. 27 Не забываем! __proto__ лучше установить явно – через оператор new
  • 28. 28 var Grandfather = function () {}; // Конструктор Grandfather Grandfather.prototype.color = 'green'; var Father = function () {}; // Конструктор Father Father.prototype = new Grandfather(); // Наследуем var Son = function () {}; // Конструктор Son Son.prototype = new Father(); // Наследуем var g = new Grandfather(); // Экземпляр "класса" Grandfather var f = new Father(); // Экземпляр "класса" Father var s = new Son(); // Экземпляр "класса" Son // Изначально все зеленые console.log([g.color, f.color, s.color]); // ["green", "green", "green"] Пример с мутантами
  • 29. 29 // Дед решил поменять свой цвет и цвет потомства Grandfather.prototype.color = 'blue'; // Все синие console.log([g.color, f.color, s.color]); // ["blue", "blue", "blue"] // Отец решил все вернуть для себя и своего потомства Father.prototype.color = 'green'; // Хотя мог исделать и так: // Grandfather.prototype.color = 'green'; // Цвет вернулся console.log([g.color, f.color, s.color]); // ["blue", "green", "green"] Пример с мутантами
  • 30. 30 // Смысла нет Grandfather.prototype.color = 'blue'; console.log([g.color, f.color, s.color]); // ["blue", "green", "green"] // Сын решил поменял только собственное свойство s.color = 'black'; console.log([g.color, f.color, s.color]); // ["blue", "green", "black"] var SonsSon = function () {}; // Конструктор SonsSon SonsSon.prototype = new Son(); // Наследуем var ss = new SonsSon(); // Экземпляр "класса" SonsSon console.log([g.color, f.color, s.color, ss.color]); // ["blue", "green", "black", "green"] Пример с мутантами
  • 31. 31 Цепочка прототипов: Grandfather g __proto__ object Grandfather.prototype color blue __proto__ object Object.prototype __proto__ null
  • 32. 32 В конце экземпляр Son будет таким. Hell Mess… var s = { color: 'black', // Поменял только собственное свойство __proto__: { // Son.prototype __proto__: { // Father.prototype color: 'green', // Отец решил вернуть цвет __proto__: { // Grandfather.prototype color: 'blue', // Дед решил поменять цвет __proto__: { // Object.prototype // Много разных свойств __proto__: null } } } } }; Цепочка прототипов: Son
  • 33. 33
  • 34. 34 А что, если в конструкторе alert(), а если он добавляет свойства?
  • 35. 35 alert('Mua-ha-ha') // Конструктор Grandfather var Grandfather = function () { alert('Mua-ha-ha'); return ["Mua-ha-ha!"]; }; Grandfather.prototype.color = 'green'; // Конструктор Father var Father = function () {}; Father.prototype = new Grandfather();
  • 36. 36 alert('Mua-ha-ha') // Конструктор Grandfather var Grandfather = function () { alert('Mua-ha-ha'); return "Mua-ha-ha!"; }; Grandfather.prototype.color = 'green'; // Конструктор Father var Father = function () {}; Father.prototype = new Grandfather();
  • 37. 37 Используется для чистого наследования цепочки прототипов new – это просто средство подмешать prototype function inherits(Constructor, SuperConstructor) { var F = function () {}; // Временный, чистый конструктор // Сохраняем ссылку F.prototype = SuperConstructor.prototype; // Применяем __proto__ = prototype Constructor.prototype = new F(); } Функция inherits или подобная var Grandfather = function () {}; // Конструктор Grandfather Grandfather.prototype.color = 'green'; var Father = function () {}; // Конструктор Father // Father.prototype = new Grandfather(); inherits(Father, Grandfather); // Наследуем
  • 38. 38 Есть еще один вариант использовать Object.create(); Только ECMAScript 5 var Grandfather = function () {}; // Конструктор Grandfather Grandfather.prototype.color = 'green'; var Father = function () {}; // Конструктор Father // Father.prototype = new Grandfather(); // Что она делает - понятно Father.prototype = Object.create(Grandfather.prototype); // Полная и абсолютно честная версия Father.prototype = Object.create(Grandfather.prototype, { constructor: { value: Father, enumerable: false, writable: true, configurable: true } }); ECMAScript 5 – Object.create()
  • 39. Оператор "точка" и [] Получение свойств
  • 41. 41 Оператор "точка" и [] •  getProperty(obj, name): *! •  Ищет в собственных свойствах •  Нет? – ищем в цепочке прототипов •  Пока __proto__ !== null •  Не нашли – возвращаем undefined
  • 42. 42 function getProperty(obj, name) { // Ищем в собственных if (obj.hasOwnProperty(name)) { return obj[name]; } // Ищем рекурсивно в цепочке прототипов else if (obj.__proto__ !== null) { return getProperty(obj.__proto__, name); } // Не нашли else { return undefined; } } // Пример getProperty(s, "color") === s.color; Оператор "точка" и [] в коде
  • 43. 43 Цепочка прототипов объекта s s color black __proto__ object Son.prototype __proto__ object Grandfather.prototype color blue __proto__ object Object.prototype __proto__ null Участок цепочки Father пропущен
  • 44. 44 Храните функции в прототипе, а данные в собственных свойствах
  • 46. 46 var u = new Grandfather(); var f = new Father(); var s = new Son(); s instanceof Son === true; // OK s instanceof Father === true; // OK? s instanceof Grandfather === true; // OK?? // Неужели множественное наследование??? s instanceof Object === true; // WAT??? s instanceof Array === false; // ОК! Оператор instanceof
  • 48. 48 Оператор instanceof •  instanceof(obj, Constructor):Boolean! •  Использует цепочку прототипов •  Рекурсивно проверяет равенство Constructor.prototype === obj.__proto__! •  До того пока __proto__ !== null – вернет false
  • 49. 49 function isInstanceOf(obj, Сonstructor) { // Нашли if (obj.__proto__ === Сonstructor.prototype) { return true; } // Ищем дальше рекурсивно else if (obj.__proto__ !== null) { return isInstanceOf(obj.__proto__, Сonstructor); } // Не нашли else { return false; } } // Пример isInstanceOf(s, Father) === s instanceof Father; Оператор instanceof в коде
  • 50. 50 Цепочка прототипов объекта s s color black __proto__ object Son.prototype __proto__ object Grandfather.prototype color blue __proto__ object Object.prototype __proto__ null Участок цепочки Father пропущен
  • 51. 51 var s = new Son(); s instanceof Array === false; // ОК! Grandfather.prototype.__proto__ = Array.prototype; s instanceof Array === true; // WAT??? Оператор instanceof
  • 52. 52 var s = new Son(); s instanceof Array === false; // ОК! Grandfather.prototype.__proto__ = Array.prototype; s instanceof Array === true; // WAT??? Оператор instanceof
  • 53. Вызов конструктора родителя Вызов метода родителя Вызов метода родителя
  • 54. 54 var Grandfather = function (name) { this.name; }; Grandfather.prototype.hello = function () { return 'I am ' + this.name; }; var Father = function (name) { Grandfather.call(this, name); }; Father.prototype.hello = function () { return Grandfather.prototype.hello.call(this) + ' – Father'; }; Вызов метода родителя
  • 55. Классы? ECMAScript 6 class Библиотеки для эмуляции классов Трансляция в JavaScript
  • 56. 56 Находится в стадии черновика спецификации class Grandfather { constructor () {} public color 'blue'; } class Father extends Grandfather { constructor () {} public color 'green'; } var f = new Father(); ECMAScript 6 class
  • 58. 58 В JavaScript нет и не будет классов. Слово class – синтаксический сахар.
  • 59. 59 Все это в конечном итоге будет цепочкой прототипов. Вот такой: var Grandfather = function () {}; // Конструктор Grandfather Grandfather.prototype.color = 'blue'; var Father = function () {}; // Конструктор Father Father.prototype = Object.create(Grandfather.prototype); Father.prototype.color = 'green'; ECMAScript 6 class
  • 62. 62 Каждый программист на JavaScript должен написать свою реализацию классов ©
  • 63. 63 Библиотеки для классов •  Mootools •  Klass •  JSClas •  … Over 9000 http://habrahabr.ru/post/132698/#comment_4404597
  • 64. 64 Mootools var Grandfather = new Class({ initialize: function () { } }); var Father = new Class({ Extends: Grandfather, initialize: function () { } }); Все они выглядят примерно так
  • 65. 65 В JavaScript нет и не будет классов. new Class – для удобства разработчика.
  • 66. Пишем на одном языке, где есть классы, а затем переделываем в JavaScript! Трансляция в JS
  • 67. 67 Много языков транслируется в JS •  CoffeeScript •  Dart •  TypeScript •  Processing •  Python, Delphi, Ruby, C++ (LLVM)
  • 68. 68 Зачем транслируют? •  Не знают JavaScript и его особенностей •  Удобно писать на 1м языке –  Python, Ruby •  Синтаксический сахар –  CoffeeScript, Dart, TypeScript •  Очень долго переписывать –  Программы на C++
  • 69. 69 Проблемы трансляции •  Может быть крайне не оптимальна –  Тормоза и лаги –  Много костылей •  На выходе плохо читаемый код –  Сделан роботами для роботов •  Отлаживать в любом случае JavaScript
  • 70. 70 Лучше применять трансляцию в JavaScript только в крайнем случае!
  • 71. Изменение базовых классов Да, их также можно менять! String.prototype Array.prototype Number.prototype …
  • 72. 72 // Чтобы не зацепить хорошие браузеры if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (searchElement) { for (var i = 0; i < this.length; i++) { if (this[i] === searchElement) { return i; } } return -1; }; } [1, 2, 3, 4].indexOf(3); // 2 Polyfill для Array#indexOf Внимание! Это не полная реализация – не используйте ее! Все, что влезло в слайд. Array indexOf method http://clck.ru/3mm5x
  • 73. 73 Number.prototype.times = function (callback) { for (var i = 0; i < this; i++) { callback(i); } }; // Пример (10).times(function (index) { console.log(index); }); // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 Number#times
  • 74. 74 Прототипы базовых классов изменяем только в крайнем случае или для polyfill!
  • 75. 75 JavaScript ООП •  Нет классов – есть прототипы •  Прототипное наследование •  Цепочка прототипов –  inherits, Object.create() •  __proto__ и prototype •  Оператор new •  Оператор instanceof •  Оператор точка и [] •  Много библиотек для классов •  Трансляция в JavaScript – крайний случай
  • 76. Основы и заблуждения насчет JavaScript http://clck.ru/0zjHr