-
Notifications
You must be signed in to change notification settings - Fork 16
inheritance model
| ⏬ |
|---|
Модель наследования JS основана на понятии прототипа
Прототип - это объект
Предшественником JS в плане прототипной модели наследования является язык
Стремление сделать синтаксис Javascript похожим на Java привело к появлению в языке таких "рудиментов", как ключевое слово new, лишенное практического смысла в языках с прототипной моделью наследования и создающее иллюзию наличия классов
Класс - это абстракция, объект - это воплощение
|
|
| ☕ Класс и объект |
|---|
|
Чашка - это абстракция, но чашка, из которой ты в данный момент пьешь чай - это объект, т.е. конкретное воплощение абстракции "чашка" Для создания конкретного экземпляра класса "чашка" в классической модели используется ключевое слово new |
| ☕ Наследование в классической модели |
|---|
|
Абстракция "чашка" вложена в другую абстракцию - "емкость", поскольку емкостью также является кастрюля, и цистерна, и колба Таким образом, класс "чашка" наследует от класса "емкость" |
Так вот:
❗ в JS наследование происходит от объекта, а не класса,
т.е. от конкретного воплощения, а не от абстракции
Другими словами, JS - очень конкретный язык 😉
Для создания объекта в JS нам достаточно сделать следующее:
var sample = {
name: "master"
}При этом у нашего объекта "магическим образом" появляется свойство __proto__:
▼ { name: "master" }
name: "master"
► __proto__: ObjectЭто свойство является ссылкой на объект prototype, который реально существует
внутри встроенного нативного объекта Object
Таким образом, наследование уже свершилось
sample наследовал от Object
Чтобы посмотреть, что же он унаследовал, давайте развернем свойство __proto__ в консоли:
▼ { name: "master" }
name: "master"
► __proto__:
► constructor: ƒ Object()
► hasOwnProperty: ƒ hasOwnProperty()
► isPrototypeOf: ƒ isPrototypeOf()
► propertyIsEnumerable: ƒ propertyIsEnumerable()
► toLocaleString: ƒ toLocaleString()
► toString: ƒ toString()
► valueOf: ƒ valueOf()
► __defineGetter__: ƒ __defineGetter__()
► __defineSetter__: ƒ __defineSetter__()
► __lookupGetter__: ƒ __lookupGetter__()
► __lookupSetter__: ƒ __lookupSetter__()
► get __proto__: ƒ __proto__()
► set __proto__: ƒ __proto__()Например, "наследство" включает метод hasOwnProperty
Давайте попробуем его использовать:
sample.hasOwnProperty( "name" ) // trueО-па, мы получили true, т.е. метод работает!
Значит, наследство благополучно получено 😸
И никаких классов!
new
Что мы знаем о функциях JS ?
- в момент вызова у них появляется ссылка на контекст вызова -
this - у них есть свойство
prototype
Как же сделать функцию конструктором?
Очевидно, нужно создать объект, на который будет ссылаться this
Отсюда логически следует, что любая функция JS может быть конструктором и без ключевого слова new
function SampleClass () {
this.name = "master"
}
var sample = new SampleClass ()в результате у экземпляра sample появляется цепочка прототипов:
▼ SampleClass { name: "master" }
name: "master"
▼ __proto__:
constructor: ƒ SampleClass()
► __proto__: Objectпервое свойство __proto__ является ссылкой на объект, который содержит:
- свойство
constructorссылка на функцию
SampleClass - еще одно свойство
__proto__ссылка на
Object
Итак, наша цепочка прототипов состоит уже из двух звеньев
и опять никаких классов...
Так зачем нам ключевое слово new ?
Только для имитации классовой модели наследования, которой нет...
А что у нас в действительности есть ?
Любая функция может быть вызвана с ключевым словом new
Вопрос в том, что происходт
Прототипом всех нативных объектов является Object
У конструктора Object есть свойство prototype
Это "генокод" всех создаваемых объектов JS
Он передается им при "рождении"
Все свойства и методы, перечисленные в свойстве prototype конструктора Object, будут доступны в каждом экземпляре создаваемого нативного объекта JS
var master = { name: "master" }
var child = { name: "child" }
var obj = {}
obj.__proto__ = child
obj.__proto__.__proto__ = masterЭкземпляр obj в консоли:
▼ {}
▼ __proto__:
name: "child"
▼ __proto__:
name: "master"
► __proto__: ObjectДобавим метод setName объекту __proto__
obj.__proto__.setName = function ( val ) {
this.name = val
}и посмотрим на объект child ( который мы не трогали ) в консоли:
▼ { name: "child", setName: ƒ }
name: "child"
▸ setName: ƒ ( val )
▸ __proto__: ObjectЭто свидетельствует о том, что свойство __proto__ экземпляра является ссылкой на объект прототипа
В обоих примерах легко отслеживается цепочка прототипов
Последним "звеном" в этой цепочке будет Object - "Адам" всех нативных объектов JS
Заканчивается цепочка прототипов null
Если возникнет необходимость создать объект без прототипа, можно проделать следующее:
var obj = Object.create( null )или так:
var obj = {}
obj.__proto__ = nullThus, свойство __proto__ есть у любого объекта, и это свойство - ссылка на объект
❓ Где будет находиться свойство
crocodileпосле выполнения кода:
var obj = {}
obj.__proto__.crocodile = "crocodile"var obj = {}
obj.valueOf ()
obj.toString ()( собственные свойства объекта Object )
А вот свойства и методы объекта Object, которые не находятся в свойстве prototype, не наследуются экземплярами, и могут быть вызваны только как свойства и методы объекта Object:
Поскольку они не передаются экземплярам, их называют статическими
var obj = {
name: "test",
type: "sample"
}
obj.__proto__.crocodile = "crocodile"
Object.getOwnPropertyNames ( obj )
Object.keys ( obj )
...Метод Object.getOwnPropertyNames возвращает массив всех собственных свойств объекта, переданного в качестве аргумента метода
(2) ["name", "type"]Метод Object.keys возвращает массив всех собственных перечислимых свойств объекта, переданного в качестве аргумента метода
(2) ["name", "type"]Выведите в консоль
Object.keys ( obj )
Object.getOwnPropertyNames ( obj )Ни первый, ни второй метод не выведут свойство crocodile, потому что это свойство не собственное ( оно находится в прототипе, т.е. является унаследованным )
А вот если итерировать obj с помощью цикла for ... in, мы получим свойство crocodile
Это означает, что свойство, добавленное нами в прототип объекта, не является собственным, но является перечислимым
Выведем в консоль свойство __proto__ конструктора Object
▼ __proto__: ƒ ()
► apply: ƒ ()
arguments: (...)
► bind: ƒ ()
► call: ƒ ()
caller: (...)
► constructor: ƒ ()
length: 0
name: ""
► toString: ƒ ()
► Symbol(Symbol.hasInstance): ƒ ()
► get arguments: ƒ ()
► set arguments: ƒ ()
► get caller: ƒ ()
► set caller: ƒ ()
► __proto__: Objectа теперь выведем в консоль свойство prototype конструктора Function
▼ prototype: ƒ ()
► apply: ƒ ()
arguments: (...)
► bind: ƒ ()
► call: ƒ ()
caller: (...)
► constructor: ƒ ()
length: 0
name: ""
► toString: ƒ ()
► Symbol(Symbol.hasInstance): ƒ ()
► get arguments: ƒ ()
► set arguments: ƒ ()
► get caller: ƒ ()
► set caller: ƒ ()
► __proto__: ObjectОчевидно, что Object наследует от Function, что логично, поскольку Object - это конструктор, т.е. функция
console.dir ( Object.__proto__.constructor.name )
// FunctionПри этом объект Function.prototype наследует от Object
( свойство Function.prototype.__proto__ является ссылкой на Object.prototype )
| ссылка на | |
|---|---|
Object.__proto__ |
Function.prototype |
Function.prototype.__proto__ |
Object.prototype |
| ⏫ |
|---|
© Irina H.Fylyppova 2018
Использование данных материалов или любой их части коммерческими школами ( курсами ) является нарушением авторских прав
| 1 | 2 | 3 | 4 | 5 |
| 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 |
| ⏬ |
|---|
- Блок-схема алгоритма
- Developer Tools
- Chrome DevTools
- Переменные
- Оператор typeof
- Структуры данных
- Операторы присваивания
- Логические выражения
- Условные операторы
- Инкремент
- Свойство length
- Оператор цикла for
- UTF-8
Homework
- Приведение типов
- NaN | null | Infinity
- BigInt (ES10)
- Функции
- Методы
- Методы строк
- Методы массивов
- Date ()
Самостоятельная работа
Практика (XSS)
Homework
- Циклы while и do...while
- Циклы for...of и for...in
- Параметры по умолчанию
- Объект function
Практика
Homework
- Нативные и host-объекты
- Литерал объекта
- Унаследованные свойства
- Конструктор
- Модель наследования
- Публичные и приватные свойства
- Оператор in
1
Homework
- Итерирующие методы массивов
- Тестирование производительности
- SHA
Homework
- Размеры и прокрутка элемента
- Event Loop
- async | await
- API
- REST | HATEOAS
- status codes
JSON placeholder-
JSON server
fake chat
Homework
- strict mode
- Вычисляемые имена свойств
- Краткий синтаксис методов
- Краткий литерал объекта
- Классы
Homework
- :not(:defined)
- Shadow DOM
- Custom elements
- Lifecycle hooks
- whenDefined
- <template>
- slot
1
2
3
Homework
- npm
- webpack
Упражнение 1- ES6 модули
Упражнение 2- --mode | --watch
Упражнение 3
Упражнение 4
Упражнение 5
Упражнение 6
Упражнение 7
Упражнение 8
Homework
| ⏫ |
|---|


Дополнительно
Справочная инфо
Git Bush
TCP/IP
Коды символов