notes_js.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  1. // prettier-ignore
  2. //
  3. //
  4. try {
  5. something;
  6. } catch (e) {
  7. window.location.href = "http://stackoverflow.com/search?q=[js] + " + e.massage;
  8. }
  9. //
  10. //
  11. //
  12. // Object.entries() метод возвращает массив собственных перечисляемых свойств указанного
  13. объекта в формате[key, value],
  14. // в том же порядке, что и в цикле for...in (разница в том, что for-in перечисляет свойства
  15. из цепочки прототипов).
  16. // Порядок элементов в массиве который возвращается Object.entries() не зависит от того как
  17. объект обьявлен.
  18. // Если существует необходимость в определенном порядке, то массив должен быть отсортирован
  19. до вызова метода,
  20. // например Object.entries(obj).sort((a, b) => a[0] - b[0]);.
  21. for (let i in persons) {
  22. for (let [key, value] of Object.entries(persons[i])) {
  23. console.log(`${key}: ${value}`);
  24. str += `<tr><td>${key}</td><td>${value}</td></tr>`;
  25. }
  26. }
  27. //
  28. //---------------------------- если надо развернуть в линию многомерный массив
  29. predictArray
  30. .reduce(function (a, b) {
  31. return a.concat(b);
  32. })
  33. .reduce(function (a, b) {
  34. return a.concat(b);
  35. })
  36. .reduce(function (a, b) {
  37. return a.concat(b);
  38. });
  39. //
  40. //----------------------------------Многомерный массив
  41. // for (i = 0; i < 2; i++) {
  42. // predictArray[i] = [];
  43. // for (j = 0; j < 2; j++) {
  44. // predictArray[i][j] = [];
  45. // for (k = 0; k < 2; k++) {
  46. // predictArray[i][j][k] = [];
  47. // for (l = 0; l < 2; l++) {
  48. // predictArray[i][j][k][l] = (-1);
  49. // }
  50. // }
  51. // }
  52. // }
  53. //Вместо этих 4-х вложенных циклов можно одной строкой
  54. predictArray = Array.from(Array(2), () =>
  55. Array.from(Array(2), () => Array.from(Array(2), () => Array.from(Array(2), () => -1)))
  56. );
  57. //
  58. // ----------------------------------------------------------------------
  59. let arg = [].slice.call(arguments, 2);
  60. arg = arg[0].filter(index => index != undefined)
  61. // ----------------------------------------------------------------------
  62. / HTML th optional
  63. // Переработайте вывод persons в HTML с поиском всех возможных колонок во всех записях, выводом названий колонок в заголовок HTML-таблицы. Для решения этой задачи вначале узнайте множество полей (ключей) во всех записях (они не совпадают), выведите HTML-заголовок используя тэги <th>, а потом выводите все записи. Ниже выведите все персоны построчно. Следите за корректностью колонок. Для этого вам нужно итерировать общий набор колонок, а не каждую персону, колонки из которой могут отличаться от предыдущей.
  64. var arrHead = Array.from(new Set(persons.map(objPerson => Object.keys(objPerson)).flat())) // ОРГАЗМ!
  65. // Array.from(new Set( убрать дубликаты
  66. // persons.map( перечисление
  67. // objPerson => Object.keys(objPerson) взять ключи объекта
  68. // ).flat() сделать массив одномерным
  69. // ))
  70. // https://webformyself.com/kak-proizvesti-udalenie-dublej-massiva-v-es6/ - способы убрать дубликаты
  71. //
  72. //
  73. // ----------------------------------------дата-год
  74. new Date().getFullYear();
  75. //
  76. // ----------------------------------------------- JSON
  77. // JSON.stringify(value[, replacer[, space]])
  78. // Параметры
  79. // value
  80. // Значение, преобразуемое в строку JSON.
  81. // replacer Необязательный
  82. // Если является функцией, преобразует значения и свойства по ходу их преобразования в строку;
  83. // если является массивом, определяет набор свойств, включаемых в объект в окончательной строке.
  84. // Подробное описание функции replacer даётся в статье Использование родного
  85. объекта JSON руководства по JavaScript.
  86. // space Необязательный
  87. // Делает результат красиво отформатированным (расставляя пробелы).
  88. // Пример использования параметра replacer
  89. var foo = {
  90. foundation: "Mozilla",
  91. model: "box",
  92. week: 45,
  93. transport: "car",
  94. month: 7,
  95. };
  96. JSON.stringify(foo, function (key, value) {
  97. if (typeof value === "string") {
  98. return undefined; // удаляем все строковые свойства
  99. }
  100. return value;
  101. }); // '{"week":45,"month":7}'
  102. JSON.stringify(foo, ["week", "month"]);
  103. // '{"week":45,"month":7}', сохранились только свойства week и month
  104. //
  105. // --------------------------------------------------------- ДЕСТРУКТУРИЗАЦИЯ
  106. // destruct array
  107. // напишите код, который используя деструктуризацию положит:
  108. // четные числа в переменные even1, even2,
  109. // нечетные в odd1, odd2, odd3,
  110. // буквы в отдельный массив
  111. let arr = [1, 2, 3, 4, 5, "a", "b", "c"];
  112. let [odd1, even1, odd2, even2, odd3, ...charArr] = arr;
  113. // destruct string
  114. // напишите код, который используя деструктуризацию положит:
  115. // число в переменную number
  116. // букву a в переменную s1
  117. // букву b в переменную s2
  118. // букву c в переменную s3
  119. let arr = [1, "abc"];
  120. let [number, [s1, s2, s3]] = arr;
  121. // destruct 2
  122. // извлеките используя деструктуризацию имена детей в переменные name1 и name2
  123. let obj = {
  124. name: "Ivan",
  125. surname: "Petrov",
  126. children: [{ name: "Maria" }, { name: "Nikolay" }],
  127. };
  128. // let { children } = obj;
  129. // let [{ name: name1 }, { name: name2 }] = children;
  130. let {
  131. children: [{ name: name1 }, { name: name2 }],
  132. } = obj;
  133. // desctruct 3
  134. // let arr = [1, 2, 3, 4, 5, 6, 7, 10]
  135. // извлеките используя деструктуризацию объектов два первых элемента
  136. // и длину массива в переменные a, b и length
  137. let arr = [77, 25, 3, 4, 5, 6, 7, 10];
  138. let { length: length, [0]: a, [1]: b } = arr;
  139. //
  140. // ---------------------------------------------------------
  141. // События mouseover/mouseout, relatedTarget
  142. // Событие mouseover происходит в момент, когда курсор оказывается над элементом, а событие
  143. mouseout – в момент, когда курсор уходит с элемента.
  144. // Эти события являются особенными, потому что у них имеется свойство relatedTarget.
  145. Оно «дополняет» target.
  146. // Когда мышь переходит с одного элемента на другой, то один из них будет target,
  147. а другой relatedTarget.
  148. // Для события mouseover:
  149. // event.target – это элемент, на который курсор перешёл.
  150. // event.relatedTarget – это элемент, с которого курсор ушёл (relatedTarget → target).
  151. // Для события mouseout наоборот:
  152. // event.target – это элемент, с которого курсор ушёл.
  153. // event.relatedTarget – это элемент, на который курсор перешёл (target → relatedTarget).
  154. // Событие mouseover, происходящее на потомке, всплывает. Поэтому если на родительском
  155. элементе есть такой обработчик, то оно его вызовет.
  156. //-------------------------------------------------------
  157. // События mouseenter и mouseleave
  158. // События mouseenter / mouseleave похожи на mouseover / mouseout.
  159. // Они тоже генерируются, когда курсор мыши переходит на элемент или покидает его.
  160. // Но есть и пара важных отличий:
  161. // Переходы внутри элемента, на его потомки и с них, не считаются.
  162. // События mouseenter/mouseleave не всплывают.
  163. // События mouseenter/mouseleave предельно просты и понятны.
  164. // Когда указатель появляется над элементом – генерируется mouseenter,
  165. // причём не имеет значения, где именно указатель: на самом элементе или на его потомке.
  166. // Событие mouseleave происходит, когда курсор покидает элемент.
  167. //-------------------------------------------------------
  168. // Object.keys, values, entries
  169. // Давайте отойдём от отдельных структур данных и поговорим об их переборе вообще.
  170. // В предыдущей главе мы видели методы map.keys(), map.values(), map.entries().
  171. // Это универсальные методы, и существует общее соглашение использовать их для структур данных.
  172. // Если бы мы делали собственную структуру данных, нам также следовало бы их реализовать.
  173. // Методы поддерживаются для структур:
  174. // Map
  175. // Set
  176. // Array
  177. // Простые объекты также можно перебирать похожими методами, но синтаксис немного отличается.
  178. // Object.keys, values, entries
  179. // Для простых объектов доступны следующие методы:
  180. // Object.keys(obj) – возвращает массив ключей.
  181. // Object.values(obj) – возвращает массив значений.
  182. // Object.entries(obj) – возвращает массив пар [ключ, значение].
  183. // Object.keys/values/entries игнорируют символьные свойства
  184. // Так же, как и цикл for..in, эти методы игнорируют свойства, использующие Symbol(...)
  185. в качестве ключей.
  186. // Обычно это удобно. Но если требуется учитывать и символьные ключи, то для этого существует
  187. отдельный метод
  188. // Object.getOwnPropertySymbols, возвращающий массив только символьных ключей.
  189. // Также, существует метод Reflect.ownKeys(obj), который возвращает все ключи.
  190. let prices = {
  191. banana: 1,
  192. orange: 2,
  193. meat: 4,
  194. };
  195. let doublePrices = Object.fromEntries(
  196. // преобразовать в массив, затем map, затем fromEntries обратно объект
  197. Object.entries(prices).map(([key, value]) => [key, value * 2])
  198. );
  199. alert(doublePrices.meat); // 8
  200. //-------------------------------------------------------
  201. Итого
  202. Методы для создания узлов:
  203. document.createElement(tag) – создаёт элемент с заданным тегом,
  204. document.createTextNode(value) – создаёт текстовый узел (редко используется),
  205. elem.cloneNode(deep) – клонирует элемент, если deep==true, то со всеми дочерними элементами.
  206. Вставка и удаление:
  207. node.append(...nodes or strings) – вставляет в node в конец,
  208. node.prepend(...nodes or strings) – вставляет в node в начало,
  209. node.before(...nodes or strings) – вставляет прямо перед node,
  210. node.after(...nodes or strings) – вставляет сразу после node,
  211. node.replaceWith(...nodes or strings) – заменяет node.
  212. node.remove() – удаляет node.
  213. Устаревшие методы:
  214. parent.appendChild(node)
  215. parent.insertBefore(node, nextSibling)
  216. parent.removeChild(node)
  217. parent.replaceChild(newElem, node)
  218. Все эти методы возвращают node.
  219. Если нужно вставить фрагмент HTML, то elem.insertAdjacentHTML(where, html) вставляет в
  220. зависимости от where:
  221. "beforebegin" – вставляет html прямо перед elem,
  222. "afterbegin" – вставляет html в elem в начало,
  223. "beforeEnd" – вставляет html в elem в конец,
  224. "afterend" – вставляет html сразу после elem.
  225. Также существуют похожие методы elem.insertAdjacentText и elem.insertAdjacentElement, они
  226. вставляют текстовые строки и элементы,
  227. но они редко используются.
  228. Чтобы добавить HTML на страницу до завершения её загрузки:
  229. document.write(html)
  230. После загрузки страницы такой вызов затирает документ.В основном встречается в старых скриптах.
  231. //
  232. //
  233. =============== sort Input
  234. sel - noda
  235. const sortInput = function (sel) {
  236. var arr = Array.from(sel.children).sort((x, y) => {
  237. return x.text.localeCompare(y.text);
  238. });
  239. arr.forEach((x) => sel.appendChild(x));
  240. sel.selectedIndex = 0;
  241. };
  242. // --------- bind
  243. // у функций есть встроенный метод bind, который позволяет зафиксировать this.
  244. // Базовый синтаксис bind:
  245. let boundFunc = func.bind(context, [arg1], [arg2], ...);
  246. // Другими словами, вызов boundFunc подобен вызову func с фиксированным this.
  247. // Это позволяет привязать контекст this и начальные (!!!) аргументы функции.
  248. let user = {
  249. firstName: "Вася"
  250. };
  251. function func() {
  252. alert(this.firstName);
  253. }
  254. let funcUser = func.bind(user);
  255. funcUser(); // Вася
  256. // ------
  257. function mul(a, b) {
  258. return a * b;
  259. }
  260. let double = mul.bind(null, 2);
  261. alert( double(3) ); // = mul(2, 3) = 6
  262. alert( double(4) ); // = mul(2, 4) = 8
  263. alert( double(5) ); // = mul(2, 5) = 10
  264. //
  265. // Частичное применение без контекста
  266. // Что если мы хотим зафиксировать некоторые аргументы, но не контекст this? Например,
  267. для метода объекта.
  268. // Встроенный bind не позволяет этого. Мы не можем просто опустить контекст и перейти к аргументам.
  269. // К счастью, легко создать вспомогательную функцию partial, которая привязывает только аргументы.
  270. // Вот так:
  271. function partial(func, ...argsBound) {
  272. return function(...args) { // (*)
  273. return func.call(this, ...argsBound, ...args);
  274. }
  275. }
  276. // использование:
  277. let user = {
  278. firstName: "John",
  279. say(time, phrase) {
  280. alert(`[${time}] ${this.firstName}: ${phrase}!`);
  281. }
  282. };
  283. // добавляем частично применённый метод с фиксированным временем
  284. user.sayNow = partial(user.say, new Date().getHours() + ':' + new Date().getMinutes());
  285. user.sayNow("Hello");
  286. // Что-то вроде этого:
  287. // [10:00] John: Hello!
  288. // Существует специальный встроенный метод функции func.call(context, …args),
  289. // который позволяет вызывать функцию, явно устанавливая this.
  290. // Синтаксис:
  291. func.call(context, arg1, arg2, ...)
  292. // Метод call() вызывает функцию с указанным значением this и индивидуально предоставленными
  293. аргументами.
  294. // Примечание: хотя синтаксис этой функции практически полностью идентичен функции apply(),
  295. // фундаментальное различие между ними заключается в том,
  296. // что функция call() принимает список аргументов,
  297. // в то время, как функция apply() - одиночный массив аргументов.
  298. // Вместо func.call(this, ...arguments) мы могли бы написать func.apply(this, arguments).
  299. // Синтаксис встроенного метода func.apply:
  300. func.apply(context, args)
  301. // Он выполняет func, устанавливая this = context и принимая в качестве списка аргументов
  302. псевдомассив args.
  303. // Единственная разница в синтаксисе между call и apply состоит в том, что call ожидает список
  304. аргументов,
  305. // в то время как apply принимает псевдомассив.
  306. // Эти два вызова почти эквивалентны:
  307. func.call(context, ...args); // передаёт массив как список с оператором расширения
  308. func.apply(context, args); // тот же эффект
  309. // Есть только одна небольшая разница:
  310. // Оператор расширения ... позволяет передавать перебираемый объект args в виде списка в call.
  311. // А apply принимает только псевдомассив args.
  312. // Так что эти вызовы дополняют друг друга. Для перебираемых объектов сработает call, а где мы
  313. ожидаем псевдомассив – apply.
  314. // А если у нас объект, который и то, и другое, например, реальный массив, то технически мы могли
  315. бы использовать любой метод,
  316. // но apply, вероятно, будет быстрее, потому что большинство движков JavaScript внутренне
  317. оптимизируют его лучше.
  318. // Передача всех аргументов вместе с контекстом другой функции называется «перенаправлением
  319. вызова» (call forwarding).
  320. // Простейший вид такого перенаправления:
  321. let wrapper = function() {
  322. return func.apply(this, arguments);
  323. };
  324. // При вызове wrapper из внешнего кода его не отличить от вызова исходной функции.
  325. // ==========================================================================================
  326. =====================================
  327. Итого
  328. Типовой код для GET-запроса при помощи XMLHttpRequest:
  329. var xhr = new XMLHttpRequest();
  330. xhr.open('GET', '/my/url', true);
  331. xhr.send();
  332. xhr.onreadystatechange = function() {
  333. if (this.readyState != 4) return;
  334. // по окончании запроса доступны:
  335. // status, statusText
  336. // responseText, responseXML (при content-type: text/xml)
  337. if (this.status != 200) {
  338. // обработать ошибку
  339. alert( 'ошибка: ' + (this.status ? this.statusText : 'запрос не удался') );
  340. return;
  341. }
  342. // получить результат из this.responseText или this.responseXML
  343. }
  344. Мы разобрали следующие методы XMLHttpRequest:
  345. open(method, url, async, user, password)
  346. send(body)
  347. abort()
  348. setRequestHeader(name, value)
  349. getResponseHeader(name)
  350. getAllResponseHeaders()
  351. Свойства XMLHttpRequest:
  352. timeout
  353. responseText
  354. responseXML
  355. status
  356. statusText
  357. События:
  358. onreadystatechange
  359. ontimeout
  360. onerror
  361. onload
  362. onprogress
  363. onabort
  364. onloadstart
  365. onloadend
  366. xhr.onload = function() {
  367. if (xhr.status != 200) { // анализируем HTTP-статус ответа, если статус не 200, то произошла ошибка
  368. alert(`Ошибка ${xhr.status}: ${xhr.statusText}`); // Например, 404: Not Found
  369. } else { // если всё прошло гладко, выводим результат
  370. alert(`Готово, получили ${xhr.response.length} байт`); // response -- это ответ сервера
  371. }
  372. };
  373. ----------------Кросс-браузерно:-----------------------
  374. var XHR = ("onload" in new XMLHttpRequest()) ? XMLHttpRequest : XDomainRequest;
  375. var xhr = new XHR();
  376. Теперь в IE8,9 поддерживаются события onload, onerror и onprogress. Это именно для IE8,9.
  377. Для IE10 обычный XMLHttpRequest уже является полноценным.
  378. ============= PROMISE =========
  379. //
  380. let del3000ms = new Promise(function (ok, fail) {
  381. setTimeout(() => ok("vse super"), 3000);
  382. });
  383. //
  384. del3000ms
  385. .then((res) => res.toUpperCase())
  386. .then(
  387. (res2) => console.log(res2),
  388. (err) => console.log("Uuuups")
  389. );
  390. //
  391. let delay = (ms) => new Promise((ok) => setTimeout(() => ok(ms), ms));
  392. delay(1000)
  393. .then(() => console.log("wait"))
  394. .then(() => delay(2000))
  395. .then(() => console.log("wait twice"));
  396. let promise = new Promise((resolve, reject) => {
  397. setTimeout(() => {
  398. // переведёт промис в состояние fulfilled с результатом "result"
  399. resolve("result1111");
  400. }, 3000);
  401. });
  402. // promise.then навешивает обработчики на успешный результат или ошибку
  403. promise.then(
  404. (result) => {
  405. // первая функция-обработчик - запустится при вызове resolve
  406. alert("Fulfilled: " + result); // result - аргумент resolve
  407. },
  408. (error) => {
  409. // вторая функция - запустится при вызове reject
  410. alert("Rejected: " + error); // error - аргумент reject
  411. }
  412. );
  413. ====================================================================================
  414. ====================================================================================
  415. ====================================================================================
  416. ====================================================================================
  417. ====================================================================================
  418. ====================================================================================
  419. ====================================================================================
  420. ====================================================================================
  421. ====================================================================================
  422. ====================================================================================
  423. ====================================================================================
  424. let user = {
  425. name: "John"
  426. };
  427. let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
  428. alert( JSON.stringify(descriptor, null, 2 ) );
  429. /* дескриптор свойства:
  430. {
  431. "value": "John",
  432. "writable": true,
  433. "enumerable": true,
  434. "configurable": true
  435. }
  436. */
  437. Чтобы изменить флаги, мы можем использовать метод Object.defineProperty.
  438. Его синтаксис:
  439. Object.defineProperty(obj, propertyName, descriptor)
  440. obj, propertyName
  441. Объект и его свойство, для которого нужно применить дескриптор.
  442. descriptor
  443. Применяемый дескриптор.
  444. Если свойство существует, defineProperty обновит его флаги. В противном случае метод
  445. создаёт новое свойство с указанным значением и флагами; если какой-либо флаг не указан явно,
  446. ему присваивается значение false.
  447. Object.defineProperty(user, "name", {
  448. writable: false
  449. });
  450. Теперь никто не сможет изменить имя пользователя, если только не обновит соответствующий флаг
  451. новым вызовом defineProperty.
  452. Ошибки появляются только в строгом режиме
  453. В нестрогом режиме, без use strict, мы не увидим никаких ошибок при записи в свойства
  454. «только для чтения» и т.п. Но эти операции всё равно не будут выполнены успешно.
  455. Действия, нарушающие ограничения флагов, в нестрогом режиме просто молча игнорируются.
  456. Определение свойства как неконфигурируемого – это дорога в один конец.
  457. Мы не сможем отменить это действие, потому что defineProperty не работает
  458. с неконфигурируемыми свойствами.
  459. Object.getOwnPropertyDescriptors
  460. Чтобы получить все дескрипторы свойств сразу, можно воспользоваться методом
  461. Object.getOwnPropertyDescriptors(obj).
  462. Вместе с Object.defineProperties этот метод можно использовать для клонирования
  463. объекта вместе с его флагами:
  464. let clone = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj));
  465. Обычно при клонировании объекта мы используем присваивание, чтобы скопировать его свойства:
  466. for (let key in user) {
  467. clone[key] = user[key]
  468. }
  469. …Но это не копирует флаги. Так что если нам нужен клон «получше», предпочтительнее и
  470. спользовать Object.defineProperties.
  471. Другое отличие в том, что for..in игнорирует символьные свойства,
  472. а Object.getOwnPropertyDescriptors возвращает дескрипторы всех свойств, включая свойства-символы.
  473. Глобальное запечатывание объекта
  474. Дескрипторы свойств работают на уровне конкретных свойств.
  475. Но ещё есть методы, которые ограничивают доступ ко всему объекту:
  476. Object.preventExtensions(obj)
  477. Запрещает добавлять новые свойства в объект.
  478. Object.seal(obj)
  479. Запрещает добавлять/удалять свойства. Устанавливает configurable: false для всех существующих свойств.
  480. Object.freeze(obj)
  481. Запрещает добавлять/удалять/изменять свойства.
  482. Устанавливает configurable: false, writable: false для всех существующих свойств.
  483. А также есть методы для их проверки:
  484. Object.isExtensible(obj)
  485. Возвращает false, если добавление свойств запрещено, иначе true.
  486. Object.isSealed(obj)
  487. Возвращает true, если добавление/удаление свойств запрещено и для всех существующих
  488. свойств установлено configurable: false.
  489. Object.isFrozen(obj)
  490. Возвращает true, если добавление/удаление/изменение свойств запрещено,
  491. и для всех текущих свойств установлено configurable: false, writable: false.
  492. На практике эти методы используются редко.
  493. Итого
  494. Чтобы унаследовать от класса: class Child extends Parent:
  495. При этом Child.prototype.__proto__ будет равен Parent.prototype, так что методы будут унаследованы.
  496. При переопределении конструктора:
  497. Обязателен вызов конструктора родителя super() в конструкторе Child до обращения к this.
  498. При переопределении другого метода:
  499. Мы можем вызвать super.method() в методе Child для обращения к методу родителя Parent.
  500. Внутренние детали:
  501. Методы запоминают свой объект во внутреннем свойстве [[HomeObject]]. Благодаря этому работает super,
  502. он в его прототипе ищет родительские методы.
  503. Поэтому копировать метод, использующий super, между разными объектами небезопасно.
  504. Также:
  505. У функций-стрелок нет своего this и super, поэтому они «прозрачно» встраиваются во внешний контекст.