SlideShare a Scribd company logo
1 of 77
Download to read offline
Михаил Давыдов
Разработчик 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
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

Viewers also liked

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

Viewers also liked (11)

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

Similar to JavaScript. OOP (in russian)

Михаил Давыдов: JavaScript. Базовые знания
Михаил Давыдов: JavaScript. Базовые знанияМихаил Давыдов: JavaScript. Базовые знания
Михаил Давыдов: JavaScript. Базовые знанияYandex
 
Очень вкусный фрукт Guava
Очень вкусный фрукт GuavaОчень вкусный фрукт Guava
Очень вкусный фрукт GuavaEgor Chernyshev
 
ООП в JavaScript
ООП в JavaScriptООП в JavaScript
ООП в JavaScriptenterra-inc
 
JavaScript не нужен, CoffeeScript - мимими
JavaScript не нужен, CoffeeScript - мимимиJavaScript не нужен, CoffeeScript - мимими
JavaScript не нужен, CoffeeScript - мимимиEvgeny Vlasenko
 
Зачем нужна Scala?
Зачем нужна Scala?Зачем нужна Scala?
Зачем нужна Scala?Vasil Remeniuk
 
Артем Яворский "@babel/core": "7.x"
Артем Яворский "@babel/core": "7.x"Артем Яворский "@babel/core": "7.x"
Артем Яворский "@babel/core": "7.x"Fwdays
 
Михаил Давыдов — JavaScript: Базовые знания
Михаил Давыдов — JavaScript: Базовые знанияМихаил Давыдов — JavaScript: Базовые знания
Михаил Давыдов — JavaScript: Базовые знанияYandex
 
O Babel 7 и немного больше, Артем Яворский
O Babel 7 и немного больше, Артем ЯворскийO Babel 7 и немного больше, Артем Яворский
O Babel 7 и немного больше, Артем ЯворскийSigma Software
 
Поговорим о JavaScript, основы и современные тенденции развития языка
Поговорим о JavaScript, основы и современные тенденции развития языкаПоговорим о JavaScript, основы и современные тенденции развития языка
Поговорим о JavaScript, основы и современные тенденции развития языкаAlexander Kucherenko
 
Groovy presentation.
Groovy presentation.Groovy presentation.
Groovy presentation.Infinity
 
Михаил Давыдов - JavaScript. Базовые знания
Михаил Давыдов - JavaScript. Базовые знанияМихаил Давыдов - JavaScript. Базовые знания
Михаил Давыдов - JavaScript. Базовые знанияYandex
 
Михаил Давыдов - Транспорт, ajax
Михаил Давыдов - Транспорт, ajaxМихаил Давыдов - Транспорт, ajax
Михаил Давыдов - Транспорт, ajaxYandex
 
JavaScript: хороший тон клиентской разработки
JavaScript: хороший тон клиентской разработкиJavaScript: хороший тон клиентской разработки
JavaScript: хороший тон клиентской разработкиGetDev.NET
 
Plugin for plugin, or extending android new build system
Plugin for plugin, or extending android new build systemPlugin for plugin, or extending android new build system
Plugin for plugin, or extending android new build systemAnton Rutkevich
 
TypeScript: особенности разработки / Александр Майоров (Tutu.ru)
TypeScript: особенности разработки / Александр Майоров (Tutu.ru)TypeScript: особенности разработки / Александр Майоров (Tutu.ru)
TypeScript: особенности разработки / Александр Майоров (Tutu.ru)Ontico
 
Groovy jug-moscow-part 1
Groovy jug-moscow-part 1Groovy jug-moscow-part 1
Groovy jug-moscow-part 1Evgeny Borisov
 
Объектное и прототипное программирование в Javascript
Объектное и прототипное программирование в JavascriptОбъектное и прототипное программирование в Javascript
Объектное и прототипное программирование в JavascriptDenis Latushkin
 
модульное тестирование для Perl. алексей шруб. зал 4
модульное тестирование для Perl. алексей шруб. зал 4модульное тестирование для Perl. алексей шруб. зал 4
модульное тестирование для Perl. алексей шруб. зал 4rit2011
 

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

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

JavaScript. OOP (in russian)

  • 1.
  • 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
  • 57.
  • 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