-
Notifications
You must be signed in to change notification settings - Fork 0
Class
Синтаксический сахар на поверхности прототипной модели наследования
class declaration | class expression |
---|---|
Потеря контекста |
static |
get & set | extends |
super | ☕ Пример |
strict mode
( даже если вы не использовали директиву **_'use strict'_** )
{
}
Внутри фигурных скобок объявляются конструктор ( constructor ) и методы класса
Метод constructor создает и инициализирует экземпляра класса
"Под капотом" работает все та же прототипная модель наследования JS
Создаваемые в конструкторе класса свойства и методы могут быть приватными и публичными
( как и в обычном конструкторе )
В обычном конструкторе контекстом вызова приватных методов будет глобальный объект window
В конструкторе класса приватные методы теряют контекст ( undefined
)
class User {
constructor ( name ) {
var privateVar = prompt ( "Set privateVar value: " )
function showPrivate () {
console.log ( `Ай-яй-яй, у меня контекст вызова ${this}` )
console.log ( `Зато я вижу приватную переменную: ${privateVar}` )
}
this.name = name || "Бегемот"
this.show = function () {
showPrivate ()
}
}
}
var user = new User ( "Крокодил" )
user.show()
Ай-яй-яй, у меня контекст вызова undefined
Зато я вижу приватную переменную: 789
Для того, чтобы избавиться от иллюзий по поводу "классов" в JS,
создадим аналогичный экземпляр с помощью обычного конструктора
function User ( name ) {
var privateVar = prompt ( "Set privateVar value: " )
function showPrivate () {
console.log ( `Ай-яй-яй, у меня контекст вызова ${this}` )
console.log ( `Зато я вижу приватную переменную: ${privateVar}` )
}
this.name = name || "Бегемот"
this.show = function () {
showPrivate ()
}
}
var user = new User ( "Крокодил" )
user.show()
Ай-яй-яй, у меня контекст вызова [object Window]
Зато я вижу приватную переменную: 789
Выведем в консоль оба варианта user и найдем те косметические отличия, которые там должны быть 😉
-
constructor: class User
/constructor: ƒ User( name )
⏫ |
---|
объявление класса дожно быть раньше первого обращения к нему
Классы - это специальные функции-"обертки", в которые "заворачивают" конструктор
class Picture {
constructor ( url, width ) {
this.elem = document.createElement ( 'img' )
this.elem.src = url
this.width = width
}
}
typeof Picture // "function"
⚠️ объявленный класс невозможно удалить динамически, без перезагрузки страницы
В примере
1️⃣идентификатор
Picture
уже занят, и никакие магические заклинания не помогут переопределить его содержание
⚠️ если обычный конструктор JS можно вызвать и как функцию, и как конструктор ( с ключевым словом
new
), то конструктор класса вызвать без ключевого слова
new
нельзя - будет сгенерировано исключение
TypeError
`
let x = new Picture ( "http://www.radioactiva.cl/wp-content/uploads/2018/05/pikachu.jpg", 200 )
document.body.appendChild ( x.elem )
⏫ |
---|
let Picture = class {
constructor ( url = "https://cdn.pastemagazine.com/www/articles/GrinchPOster_header.jpg" ) {
this.elem = document.body.appendChild (
document.createElement ( 'img' )
)
this.elem.src = url
}
}
console.dir ( Picture )
▼ class Picture
arguments: (...)
caller: (...)
length: 0
name: "Picture"
► prototype: {constructor: ƒ}
► __proto__: ƒ ()
Однако если мы создадим экземпляр этого класса, и посмотрим на него в консоли, то мы увидим, что имя класса отсутствует
let sample = new Picture
console.log ( sample )
▼ Picture {elem: img}
elem: img
▼ __proto__:
► constructor: class
► __proto__: Object
let Picture = class Canvas {
constructor ( url = "https://cdn.pastemagazine.com/www/articles/GrinchPOster_header.jpg" ) {
this.elem = document.body.appendChild (
document.createElement ( 'img' )
)
this.elem.src = url
}
}
console.dir ( Picture )
▼ class Canvas
arguments: (...)
caller: (...)
length: 0
name: "Canvas"
► prototype: {constructor: ƒ}
► __proto__: ƒ ()
А теперь создадим экземпляр этого класса и выведем его в консоль:
let sample = new Picture
console.log ( sample )
▼ Canvas {elem: img}
elem: img
▼ __proto__:
► constructor: class Canvas
► __proto__: Object
sample instanceof Picture // true
sample instanceof Canvas
❌ Uncaught ReferenceError: Canvas is not defined
Итак, при использовании class expression имя класса становится недоступным извне
Точнее говоря, достучаться до него можно только так:
pict.constructor.name
const Sample = class Canvas {
constructor () {
this.canvas = document.createElement ( 'canvas' )
document.body.appendChild ( this.canvas )
this.resizeCanvas()
this.canvas.style.border = "1px solid #000000"
this.area = this.canvas.getContext ( "2d" )
}
resizeCanvas ( event ) {
this.canvas.width = window.innerWidth - 30
this.canvas.height = window.innerHeight - 20
}
drawLine ( points ) {
this.area.moveTo( points[0].x, points[0].y )
this.area.lineTo( points[1].x, points[1].y )
this.area.stroke()
}
}
let pict = new Sample ()
window.onresize = pict.resizeCanvas.bind ( pict )
pict.drawLine ( [ { x: 50, y: 50 }, { x: 250, y: 250 } ] )
pict.drawLine ( [ { x: 250, y: 250 }, { x: 100, y: 250 } ] )
📌 Чтобы получить имя класса, нужно использовать его свойство name:
console.log ( Sample.name ) // "Canvas"
⏫ |
---|
let drawLine = pict.drawLine
drawLine ( [ { x: 50, y: 50 }, { x: 250, y: 250 } ] )
будет сгенерировано исключение:
⛔️ Uncaught TypeError: Cannot read property 'area' of undefined
Передачу контекста вызова нужно сделать явным образом:
let drawLine = pict.drawLine.bind ( pict )
📌 Потеря контекста ( undefined ) происходит вследствие того, что весь код внутри тела класса выполняется в strict mode, хотя явного указания 'use strict' в коде класса нет
При отсутствии явного указания на объект, вызывающий метод,
в строгом режимеthis
не будет ссылкой на глобальный объектwindow
В строгом режимеthis
будетundefined
☕ 6️⃣
В этом примере контекст теряется в функции getProp(), объявленной внутри метода addSomeInfo
( внутренняя функция не наследует контекст вызова родительской )
class User {
constructor ( name ) {
this.name = name || 'unknown'
}
addSomeInfo ( props ) {
if ( !Array.isArray ( props ) ) return
function getProp ( prop ) {
this [ prop.name ] = prop.value
}
for ( var prop of props ) {
getProp ( prop )
}
}
}
Создадим экземпляр user класса User и вызовем метод addSomeInfo в контексте объекта user
var user = new User ( "Grig" )
user.addSomeInfo ([
{ name: "age", value: 25 },
{ name: "hobby", value: [ "football", "fishing" ] }
])
⛔️ Uncaught TypeError: Cannot set property 'age' of undefined
❗ Внутри функции getProp контекст вызова ( this
) оказался undefined
Теперь используем стрелочную функцию getProp, которая не теряет контекст 😉
class User {
constructor ( name ) {
this.name = name || 'unknown'
}
addSomeInfo ( props ) {
if ( !Array.isArray ( props ) ) return
var getProp = prop => this [ prop.name ] = prop.value
for ( var prop of props ) {
getProp ( prop )
}
}
}
Создадим экземпляр user и вызовем метод addSomeInfo
var user = new User ( "Grig" )
user.addSomeInfo ([
{ name: "age", value: 25 },
{ name: "hobby", value: [ "football", "fishing" ] }
])
console.log ( user )
▼ User {name: "Grig", age: 25, hobby: Array(2)}
age: 25
► hobby: (2) ["football", "fishing"]
name: "Grig"
▼ __proto__:
► addSomeInfo: addSomeInfo ( props ) { if ( !Array.isArray ( props ) ) return var getProp = prop => {…}
► constructor: class User
► __proto__: Object
⏫ |
---|
Курсы были созданы для студентов A-Level Ukraine.
Использование данных материалов или любой их части коммерческими школами ( курсами ) является нарушением авторских прав.
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
- Нативные и host-объекты
- Литерал объекта
- Унаследованные свойства
- Конструктор
- Модель наследования
- Публичные и приватные свойства
- Оператор in
1
Homework
- Итерирующие методы массивов
- Тестирование производительности
- SHA
Homework
- strict mode
- Вычисляемые имена свойств
- Краткий синтаксис методов
- Краткий литерал объекта
- Классы
Homework
- npm
- webpack
Упражнение 1
- ES6 модули
Упражнение 2
- --mode | --watch
Упражнение 3
Упражнение 4
Упражнение 5
Упражнение 6
Упражнение 7
Упражнение 8
Homework
⏫ |
---|