Содержание
- Данные
- Какие типы данных есть в JS?
- Какие типы в JS изменяемые, а какие нет?
- Что значит ссылка на переменную
- Что такое NaN? Как проверить, что переменная - NaN?
- Что значит создавать переменную через конструктор или через литерал?
- Когда при обращении к свойству объекта стоит использовать точечную нотацию, а когда квадратные скобки?
- Что произойдет, если попытаться получить несуществующее в объекте свойство?
- Что делает hasOwnProperty?
- Когда использовать null, а когда undefined?
- Какие есть способы создания глобальных переменных?
- Для чего нужна директива use strict
- Выражения
- Что такое выражения и инструкции? В чем отличия между ними?
- Чем отличаются var, let, const? Почему использование const может быть предпочтительнее?
- Что такое тернарный оператор?
- Что делает оператор for..in? Какие имеются особенности при использовании этого оператора с массивами?
- Как безопасно проверить, что переменная существует (была объявлена), и не словить ReferenceError?
- Массивы
- Способы создания массивов (литерал, конструктор, фабричные методы Array.from() и Array.of());
- Удаление элемента из массива (какие есть способы и в чем особенности)
- Свойство length у массива
- Как проверить, что в переменной лежит массив?
- Что делают, как и когда использовать следующие методы
- Функции
- Какие есть 4 шаблона вызова функции, которые задают контекст выполнения этой функции?
- Что такое рекурсия? Когда удобно её использовать?
- Что такое замыкания, и в каких случаях они могут быть полезны? Как сохранить состояние с помощью замыкания, и для чего это состояние может быть использовано?
- Как реализовать функцию bind?
- Решить такую вот проблему: пускай у нас есть массив ссылок, и наша задача — сделать так, чтобы при клике на каждую выводился alertом ее порядковый номер
- Что такое callback (функция обратного вызова)? Когда они обычно применяются?
- Что такое каррирование?
- Что такое частичное применение?
- Что такое мемоизация?
- Прототипы
- Что такое функция-конструктор? Как их создавать и как ими пользоваться?
- Что такое прототип? Какие возможности имеет/дает?
- Почему методы объекта лучше хранить в прототипе, а не в самом объекте?
- Можно ли создать инстанс функции через конструктор? И если да, то как, а если нет, то какой бы интерфейс вы реализовали бы для этой задачи?
- Как создать объект, который ни от чего не наследуется?
- Какие 3 (как минимум) способа есть отнаследоваться в JavaScript-е? В чем отличия и нюансы?
- Как в переопределенном методе у наследующего класса вызвать переопределяемый метод родительского?
- Какие есть способы навсегда привязать метод класса к его инстансу (чтобы this всегда был текущим экземпляром класса)
JS
Данные
Какие типы данных есть в JS?
- string
- number
- boolean
- null
- undefined
- symbol
- bigint
- object
- array
- function
Какие типы в JS изменяемые, а какие нет?
Примитивные типы (string, number, boolean, null, undefined, symbol, bigint) неизменяемые. Это такие типы, значения которых можно только перезаписать, но нельзя изменить. Этот механизм связан с тем, как значения переменных хранятся в памяти. Мы не пойдём слишком глубоко в эту тему, но, грубо говоря, примитивные типы ссылаются на одно и то же значение в памяти», а не примитивные — на разные.
Тип object - изменяемый
Что значит ссылка на переменную
Это способ присваивания значения переменной, который зависит от типа данных этого значения. Если некая сущность, которая присваивается переменной, имеет примитивный тип, то в переменную записывается именно значение. Если же речь идёт об объекте - то при назначении его переменной в неё записывается ссылка на него, адрес, по которому он расположен в памяти.
Что такое NaN? Как проверить, что переменная - NaN?
Значение NaN используется, чтобы сообщить об операции, результатом которой оказалось не число. В JavaScript существует пять операций, которые могут вернуть NaN:
ошибка парсинга числа (например, при попытке превратить строку в число parseInt('привет')).
результат математической операции не находится в полей действительных чисел (например, взятие корня от -1).
один из операндов в арифметической операции — NaN (5 + NaN).
результат арифметической операции не определён для переданных операндов (undefined + undefined).
арифметическая операция со строкой, кроме сложения ("привет" * 5)
NaN не равен самому себе. Проверить, что в переменной хранится NaN простым сравнением не получится. Для проверки на NaN пользуйтесь функцией Number.isNaN, которая возвращает true если переданное значение — NaN.
Что значит создавать переменную через конструктор или через литерал?
Через конструктор: const a = new Obj(); // Obj - имя класса или функции-конструктора
Через литерал: const b = {//перечислить свойства и методы}
Когда при обращении к свойству объекта стоит использовать точечную нотацию, а когда квадратные скобки?
Квадратные скобки - когда имя свойства состоит из нескольких слов или для обращения к свойству, имя которого может быть результатом выражения. В остальных случаях используем запись через точку
Что произойдет, если попытаться получить несуществующее в объекте свойство?
Вернется undefined
let obj = {};
console.log(obj.prop); // undefined
Что делает hasOwnProperty
Обычный цикл for..in не делает различия между свойствами объекта и его прототипа. Может быть нужно посмотреть, что находится именно в самом объекте, а не в прототипе. Вызов obj.hasOwnProperty(prop) возвращает true, если свойство prop принадлежит самому объекту obj, иначе false.
Когда использовать null, а когда undefined?
null - «ничего», «пусто» или «значение неизвестно»
undefined - «значение не было присвоено». Если переменная объявлена, но ей не присвоено никакого значения, то её значением будет undefined
Обычно null используется для присвоения переменной «пустого» или «неизвестного» значения, а undefined – для проверок, была ли переменная назначена.
Какие есть способы создания глобальных переменных?
Глобальная переменная - это свойство глобального объекта (window). Переменные и константы, которые объявлены вне функций, вне модулей являются глобальными, т.е. находятся в глобальной области видимости
Область видимости — это часть программы, в которой мы можем обратиться к переменной, функции или объекту. Этой частью может быть функция, блок или вся программа в целом — то есть, мы всегда находимся как минимум в одной области видимости.
Если нам нужно сделать глобальную переменную уровня всей страницы, можно явно присвоить её объекту window, тогда получить значение переменной можно обратившись к window.[имя-переменной]. Но это должно быть исключением, требующим веской причины.
Для чего нужна директива use strict
"use strict" включает строгий режим выполнения JavaScript. Эта строка должна располагаться в самом начале скрипта, иначе строгий режим не будет работать. В строгом режиме интерпретатор будет явно выбрасывать ошибки на действия, которые ранее пропускал. Если строгий режим был включён, то отключить его для файла уже нельзя.
Выражения
Что такое выражения и инструкции? В чем отличия между ними?
Выражение (expression)— это код, который после выполнения возвращает какое-либо значение. Например, 5 + 3 вернёт 8, а Math.random() — случайное число.
Инструкция (statement)— это отдельная команда в коде, которая выполняет определённое действие. Например, if позволяет создать ветвление в программе, for позволяет повторять одно и то же действие. В JavaScript все инструкции можно поделить на несколько категорий:
управление потоком выполнения (if и else, switch, throw и т.д.) итерации (for, while и т.д.) объявление значений (var, let, const) функции (function, return и т.д.) прочие (debugger, import, export)
Чем отличаются var, let, const? Почему использование const может быть предпочтительнее?
Объявление переменных при помощи ключевого слова var было в JavaScript с первых версий. Переменные var можно объявлять без присвоения им значения, в таком случае они будут равны undefined. Переменные, объявленные через var, имеют функциональную область видимости. Они доступны только в пределах текущей функции или глобального объекта, если функции нет. К переменным, объявленным при помощи ключевого слова var, можно обращаться до момента объявления. В отличие от let и const ошибки это не вызовет. Данное поведение называется hoisting - «всплытие»
Значение в переменной, созданной через let можно изменять. Стартовое значение const изменить нельзя, будь то примитивное значение или ссылка на объект. Однако объект, хранящийся в const можно мутировать. Объекты хранятся по ссылке и изменение объекта не приводит к изменению ссылки на него. Используя ключевое слово let можно объявить переменную без присвоения ей начального значения. В таком случае она будет равна undefined. При помощи const нельзя объявлять переменные без значения. К переменным let и const нельзя обращаться до их объявления в коде.
В новом коде используйте только let или const. Используйте let в тех случаях, когда значение переменной меняется. Во всех остальных используйте const. Проще всего всегда по умолчанию использовать ключевое слово const и исправлять объявление переменной на let если появляется нужда изменить её значение далее в коде
Зачем нужны константы? Константы защищают код от случайной перезаписи важных значений. Применяют константы в двух случаях:
- мы хотим объявить переменную, которая хранит фундаментальное значение для программы. Например, количество дней в году, минимальную сумму заказа, форматы дат и т.д.
- мы объявляем переменную и устанавливаем ей значение всего один раз
Что такое тернарный оператор?
Тернарный оператор работает с тремя операндами: одним условием и двумя выражениями. Возвращает первое выражение, если условие истинно и второе, если условие ложно: (A) ? (B) : (C). Используется как компактная замена условного оператора if.
Что делает оператор for..in? Какие имеются особенности при использовании этого оператора с массивами?
Позволяет пройти в цикле по перечисляемым свойствам объекта, в том числе по свойствам из прототипа.
Перечисляемые свойства объекта – это свойства, которые явно помечены такими. Сказать свойству, что оно перечисляемое, можно через специальный метод defineProperty. Но для простоты все свойства, которые добавляются к объекту, являются перечисляемыми по умолчанию. Встроенные свойства не перечисляется. Например метод indexOf у объекта String или метод toString у любого объекта не участвуют в цикле for...in.
В цикле будут перечислены не только собственные свойства объекта, но и все перечисляемые свойства из прототипа объекта и прототипа прототипа и так далее.
Порядок перечисления: строковые имена свойств перечисляются в порядке их присвоения к объекту, числовые - в отсортированном порядке по возрастанию. Несмотря на договорённости о порядке вывода числовых ключей, не нужно использовать for...in для перебора массива. В будущем правила могут измениться. Для перебора у массива есть собственные методы: forEach, map и другие. В этих методах порядок перебора гарантирован.
Как безопасно проверить, что переменная существует (была объявлена), и не словить ReferenceError?
===============================================================
try {
if (typeof a === 'undefined') {
console.log('Не определена');
} else console.log(a);
} catch (e) { console.log('Определена после проверки'); }
//Не определена
===============================================================
let b;
try {
if (typeof b === 'undefined') {
console.log('Не определена');
} else console.log(b);
} catch (e) { console.log('Определена после проверки'); }
//Не определена
===============================================================
try {
if (typeof c === 'undefined') {
console.log('Не определена');
} else console.log(c);
} catch (e) { console.log('Определена после проверки'); }
let c;
//Определена после проверки
===============================================================
let d = 10;
try {
if (typeof d === 'undefined') {
console.log('Не определена');
} else console.log(d);
} catch (e) { console.log('Определена после проверки'); }
// 10
===============================================================
Массивы
Способы создания массивов (литерал, конструктор, фабричные методы Array.from() и Array.of());
Литерал массива — это список из нуля или более выражений, каждое из которых представляет элемент массива, заключенный в квадратные скобки ( [] ). Когда вы создаете массив, используя литерал массива, он инициализируется с помощью переданных значений, которые будут являться его элементами, длина массива будет равна числу переданных аргументов. Синтаксис: let arr = [element0, element1, ..., elementN]
Конструктор Array(). Синтаксис: const arr = new Array(element0, element1[, ...[, elementN]]); elementN — элементы, из которых создаётся массив. Или const arr = new Array(arrayLength), arrayLength — длина массива (количество элементов )
Метод Array.of() создает новый массив из произвольного числа аргументов, независимо от их количества и типа. Разница между Array.of() и конструктором Array состоит в обработке единственного аргумента, являющегося целым числом: Array.of(7) создает массив с одним элементом, тогда как Array(7) создает пустой массив, у которого свойство length равно 7 (имеется в виду массив из 7 пустых слотов, а не слотов, содержащих значение undefined)
Array.of(7); // [7] Array(7); // array of 7 empty slots
Array.of(1, 2, 3); // [1, 2, 3] Array(1, 2, 3); // [1, 2, 3]
Удаление элемента из массива (какие есть способы и в чем особенности);
1. Метод delete (delete arr[1]). При его использовании длина массива не изменится. Удаление методом delete нормально для объектов, но для массивов мы обычно хотим, чтобы оставшиеся элементы сдвинулись и заняли освободившееся место. Мы ждём, что массив станет короче. Поэтому для этого нужно использовать метод splice.
2. Метод splice. Синтаксис: arr.splice(index[, deleteCount, elem1, ..., elemN]). Он начинает с позиции index, удаляет deleteCount элементов и вставляет elem1, ..., elemN на их место. Возвращает массив из удалённых элементов. Метод splice также может вставлять элементы без удаления, для этого достаточно установить deleteCount в 0
Свойство length у массива
Какое значение будет у свойства length массива a и почему:
const a = [1, 2, 3];
a[10] = 4;
Ответ: свойство length будет равно 11, потому что между последним элементом (3) и новым (4) появилась «дыра» из семи пустых ячеек: [1, 2, 3, empty × 7, 4]
Что будет, если переприсвоить новое значение?
Свойство length перезаписываемое, вы можете записать в него любое число из диапазона возможных значений. Это изменит количество ячеек массива. Если уменьшить значение свойства length, то из конца массива будут отброшены элементы, которые не входят в новый размер массива. Если увеличить значение свойства length, то в конец массива добавятся пустые ячейки массива. Значение в них не будет установлено и они будут игнорироваться при обходе массива. Не записывайте вручную значения в length. Хотя это и возможно, на практике такой код плохо читается. Он может неприятно удивить других разработчиков из-за того, что изменяет размер массива. Об этом побочном эффекте знают не все.
Влияет ли на length удаление элемента посередине массива? Какие способы удаления элементов влияют на длину, а какие нет?
Зависит от того, как удален элемент. Если удалять методом delete (delete arr[1]), то длина массива не изменится. Удаление методом delete нормально для объектов, но для массивов мы обычно хотим, чтобы оставшиеся элементы сдвинулись и заняли освободившееся место. Мы ждём, что массив станет короче. Поэтому для этого нужно использовать метод splice. Его синтаксис:
arr.splice(index[, deleteCount, elem1, ..., elemN])
Он начинает с позиции index, удаляет deleteCount элементов и вставляет elem1, ..., elemN на их место. Возвращает массив из удалённых элементов. Метод splice также может вставлять элементы без удаления, для этого достаточно установить deleteCount в 0
Как проверить, что в переменной лежит массив?
Метод Array.isArray() проверяет, является ли переданный аргумент массивом. Возвращает true, если является, и false — если нет.
Что делают, как и когда использовать следующие методы
reduce
Позволяет превратить массив в любое другое значение с помощью переданной функции-колбэка и начального значения. Функция-колбэк будет вызвана для каждого элемента массива и всегда должна возвращать результат. Метод reduce принимает два параметра: функцию-колбэк и начальное значение для аккумулятора.
- Сама функция-колбэк может принимать четыре параметра:
- acc — текущее значение аккумулятора
- item — элемент массива в текущей итерации
- index — индекс текущего элемента
- arr — сам массив, который мы перебираем
sort
Cортирует массив, меняя в нём порядок элементов. Он возвращает отсортированный массив, но обычно возвращаемое значение игнорируется, так как изменяется сам arr. Принимает коллбэк, описывающий, как должны сортироваться значения. Функция должна для пары значений возвращать:
function compare(a, b) {
if (a > b) return 1; // если первое значение больше второго
if (a == b) return 0; // если равны
if (a < b) return -1; // если первое значение меньше второго }
По умолчанию (если коллбэк не передан) элементы сортируются как строки.
Все указанные методы принимают коллбэк-функцию, которая принимает три параметра: item — элемент массива в текущей итерации; index — индекс текущего элемента; arr — сам массив, который мы перебираем.
filter
Позволяет получить новый массив, отфильтровав элементы с помощью переданной колбэк-функции. Колбэк-функция будет вызвана для каждого элемента массива и по результату функции примет решение включать этот элемент в новый массив или нет.
Аналогично методу forEach, методу filter необходимо передать аргументом функцию. Главное отличие — функция должна возвращать boolean, т. е. результатом должен быть true или false. Такие функции называют предикатами.
map
Метод map позволяет трансформировать один массив в другой при помощи функций-колбэка. Переданная функция будет вызвана для каждого элемента массива по порядку. Из результатов вызова функции будет собран новый массив. map возвращает новый массив, при этом исходный массив никак не изменится. При работе с map необходимо возвращать значение из функции-колбэка. Если не вернуть значение — например, забыв обработать какую-то ветку условия, то в итоговом массиве будет undefined
forEach
Выполняет функцию-коллбэк один раз для каждого элемента массива. Массив, к которому применяется метод, не изменяется
some
Позволяет узнать, есть ли в массиве хотя бы один элемент, удовлетворяющий условию в функции-колбэке. Колбэк-функция будет вызвана для каждого элемента массива до тех пор пока не вернётся true, либо пока не закончатся элементы массива. Результатом вызова метода Array.some будет boolean-значение true или false. Если ни один элемент в массиве не удовлетворит условию, то результат будет false.
every
Позволяет узнать, удовлетворяют ли все элементы в массиве условию в функции-колбэке. Результатом вызова метода Array.every будет boolean-значение true или false. Если хотя бы один элемент не будет удовлетворять условию, то результат будет false. Проверка пустого массива всегда вернёт true
Функции
Какие есть 4 шаблона вызова функции, которые задают контекст выполнения этой функции?
Вызов функции — Function Invocation. Значение this будет ссылаться на глобальный объект (window) в нестрогом режиме. В строгом режиме this равен undefined
Вызов метода — Method Invocation. Значение this будет ссылаться на объект, которому принадлежит метод
Вызов конструктора — Constructor Invocation. This в данном случае будет относиться к свежесозданному объекту
Вызов apply и call — Apply And Call Invocation. Позволяет вручную запустить функцию, попутно снабдив ее параметрами и обозначив this. Синтаксис: func.call(obj, 1, 2, 3); func.apply(obj, [1, 2, 3]);
Как директива use strict влияет на this внутри функции?
При включённом строгом режиме this больше не будет по умолчанию ссылаться на глобальный объект. This по умолчанию будет равен undefined
Какой наиболее простой паттерн, позволяющий облегчить читаемость функции, когда у нее огромное количество аргументов?
Ответ: использовать спред-синтаксис ...
спред-синтаксис:
function multiplyThreeNumbers(a, b, c) {
return a * b * c
}
const nums = [1, 2, 3, 5, 6]
console.log(multiplyThreeNumbers(...nums))
// 6
Как получить все аргументы функции (включая те, что не объявлены, но все-таки были переданы)?
Ответ: использовать остаточные параметры или переменную arguments (устаревший способ)
Остаточные параметры могут быть обозначены через три точки .... Буквально это значит: «собери оставшиеся параметры и положи их в массив».
function sumAll(...args) { // args — имя массива
let sum = 0;
for (let arg of args) sum += arg;
return sum;
}
Мы можем положить первые несколько параметров в переменные, а остальные – собрать в массив. В примере ниже первые два аргумента функции станут именем и фамилией, а третий и последующие превратятся в массив titles:
function showName(firstName, lastName, ...titles)
{// some code}
Arguments. Все аргументы функции находятся в псевдомассиве arguments под своими порядковыми номерами, к ним можно обратиться в теле функции. Недостаток этого подхода: хотя arguments похож на массив, и его тоже можно перебирать, это всё же не массив. Он не поддерживает методы массивов
Что такое замыкания, и в каких случаях они могут быть полезны? Как сохранить состояние с помощью замыкания, и для чего это состояние может быть использовано?
Как реализовать функцию bind?
Это метод, который позволяет связывать контекст выполнения с функцией, чтобы «заранее и точно» определить, какое именно значение будет у this.
function greet() {
console.log(`Hello, ${this.name}`)
}
const user1 = { name: "Alex" }
const greetAlex = greet.bind(user1)
greetAlex() // Hello, Alex
Решить такую вот проблему: пускай у нас есть массив ссылок, и наша задача — сделать так, чтобы при клике на каждую выводился alertом ее порядковый номер. Первое решение, что приходит в голову, выглядит так:
link 1 link 2 link 3 link 4 link 5
for (var i = 0; i < links.length; i++) {
links[i].onclick = function() {
alert(i);
}
}
На деле же оказывается, что при клике на любую ссылку выводится одно и то же число — значение links.length. Почему так происходит и как эту гадость исправить?
Ответ: в замыкании обработчика щелчка хранится ссылка на переменную i, а не фактическое значение i . Каждый обработчик щелчка будет ссылаться на один и тот же объект, потому что есть только один объект счетчика, который содержит i (5), поэтому вы получаете пять при каждом щелчке. Для достижения желаемого поведения необходимо var заменить на let
Что такое callback (функция обратного вызова)? Когда они обычно применяются?
В функции, которые выполняют какие-либо асинхронные операции, передаётся аргумент callback — функция, которая будет вызвана по завершению асинхронного действия.
Что такое каррирование?
Что такое частичное применение?
Что такое мемоизация?
Прототипы
Что такое функция-конструктор? Как их создавать и как ими пользоваться?
Функции-конструкторы являются обычными функциями, позволяющими создавать однотипные объекты. Есть два соглашения:
- Имя функции-конструктора должно начинаться с большой буквы.
- Функция-конструктор должна вызываться при помощи оператора "new".
- Создаётся новый пустой объект, и он присваивается this.
- Выполняется код функции. Обычно он модифицирует this, добавляет туда новые свойства.
- Возвращается значение this.
Что такое прототип? Какие возможности имеет/дает?
В JavaScript объекты имеют специальное скрытое свойство [[Prototype]] (так оно названо в спецификации), которое либо равно null, либо ссылается на другой объект. Этот объект называется «прототип».
Когда мы хотим прочитать свойство или вызвать метод из object, а оно (он) отсутствует, JavaScript автоматически берёт его из прототипа. В программировании такой механизм называется «прототипным наследованием». Прототип используется только для чтения свойств. Операции записи/удаления работают напрямую с объектом. Т.е. если изначально некле свойство (или метод) было в прототипе, а потом его с тем же именем добавили в объект, то использоваться будет свойство/ метод самого объекта, в прототипе его уже искать не будем
Неважно, где находится метод: в объекте или его прототипе. При вызове метода this — всегда объект перед точкой.
Цикл for..in проходит не только по собственным, но и по унаследованным свойствам объекта. Если унаследованные свойства нам не нужны, то мы можем отфильтровать их при помощи встроенного метода obj.hasOwnProperty(key): он возвращает true, если у obj есть собственное, не унаследованное, свойство с именем key. Почти все остальные методы, получающие ключи/значения, такие как Object.keys, Object.values и другие – игнорируют унаследованные свойства. Они учитывают только свойства самого объекта, не его прототипа.
Почему методы объекта лучше хранить в прототипе, а не в самом объекте?
Лучше с точки зрения использования памяти. Например, есть 1000 объектов, у каждого объекта в конструкторе есть метод который делает одно и тоже для каждого объекта. Занимает память? Да. Можно в прототип вынести этот метод и метод будет всего один для каждого объекта, а к нему будут вести ссылки. С точки зрения оптимизации так будет лучше.
Можно ли создать инстанс функции через конструктор? И если да, то как, а если нет, то какой бы интерфейс вы реализовали бы для этой задачи?
Создать инстанс функции через конструктор можно. На самом деле каждая JavaScript-функция является объектом Function. Это легко проверить, выполнив проверку (function(){}).constructor === Function, которая вернёт true.
Синтаксис: let func = new Function ([arg1, arg2, ...argN], functionBody);
Функции, объявленные через new Function, имеют [[Environment]], ссылающийся на глобальное лексическое окружение, а не на родительское. Поэтому они не могут использовать внешние локальные переменные.
Как создать объект, который ни от чего не наследуется?
Object.create(null) создаёт пустой объект без прототипа ([[Prototype]] будет null):
Мы можем назвать такой объект «простейшим» или «чистым словарным объектом», потому что он ещё проще, чем обычные объекты {...}. Недостаток в том, что у таких объектов не будет встроенных методов объекта, таких как toString
Какие 3 (как минимум) способа есть отнаследоваться в JavaScript-е? В чем отличия и нюансы?
Для существующего объекта:
- Устаревший способ:
- задать значение свойству __proto__: rabbit.__proto__ = animal; __proto__ — не то же самое, что [[Prototype]]. Это геттер/сеттер для него.. Встроенный геттер/сеттер __proto__ не безопасен, если мы хотим использовать созданные пользователями ключи в объекте. Как минимум потому, что пользователь может ввести "__proto__" как ключ, от чего может возникнуть ошибка. Если повезёт – последствия будут лёгкими, но, вообще говоря, они непредсказуемы. Так что мы можем использовать либо Object.create(null) для создания «простейшего» объекта, либо использовать коллекцию Map.
-
- Современные методы:
- Object.create(proto, [descriptors]) – создаёт пустой объект со свойством [[Prototype]], указанным как proto, и необязательными дескрипторами свойств descriptors. Object.create даёт нам лёгкий способ создать поверхностную копию объекта со всеми дескрипторами
- Object.getPrototypeOf(obj) – возвращает свойство [[Prototype]] объекта obj.
- Object.setPrototypeOf(obj, proto) – устанавливает свойство [[Prototype]] объекта obj как proto.
let parentObj = { //родительский объект
parentMethod: function () {
}
}
let childObj = {
childMethod: function () {
}
}
//добавление прототипа ранее созданному объекту
Object.setPrototypeOf(childObj, parentObj);
console.log(childObj);
При создании объектов с помощью функции-конструктора:
let parentObj = { //родительский объект
parentMethod: function () {
}
}
function ChildConstructorFunc() {
this.childMethod = function () {
}
}
ChildConstructorFunc.prototype = parentObj;//наследование от родительского объекта
console.log(new ChildConstructorFunc());
Установка ChildConstructorFunc.prototype = parentObj буквально говорит интерпретатору следующее: "При создании объекта через new ChildConstructorFunc() запиши ему parentObj в [[Prototype]]".
- Свойство F.prototype (не путать с [[Prototype]]) устанавливает[[Prototype]] для новых объектов при вызове new F().
- Значение F.prototype должно быть либо объектом, либо null. Другие значения не будут работать.
- Свойство "prototype" является особым, только когда оно назначено функции-конструктору, которая вызывается оператором new.
- По умолчанию все функции имеют F.prototype = { constructor: F }, поэтому мы можем получить конструктор объекта через свойство "constructor"
При создании объекта с помощью класса:
Для того, чтобы наследовать класс от другого, мы должны использовать ключевое слово "extends" и указать название родительского класса перед {..}.
class ParentClass {
parentMethod() {
}
}
class ChildClass extends ParentClass {
childMethod() {
}
}
console.log(new ChildClass());
Как в переопределенном методе у наследующего класса вызвать переопределяемый метод родительского? Пример псевдокода:
class Person
method getFullName()
return this.name + this.surname
class Employee extends Person
method getFullName()
return super() + this.position
Ответ:
class Employee extends Person
method getFullName()
return super.getFullName() + this.position