Checkpoint
https://github.com/4m9fk/developers-roadmap/blob/master/frontend/junior-1/js.md =====> (https://github.com/airbnb/javascript#types) && (https://github.com/leonidlebedev/javascript-airbnb#types)
Данные
Какие типы данных есть в JS?
Простые типы: Когда вы взаимодействуете с простым типом, вы напрямую работаете с его значением.
string
number
boolean
null
undefined
symbol
BigInt
Символы не могут быть полностью заполифиллены, поэтому они не должны использоваться, если разработка ведётся для браузеров/сред, которые не поддерживают их нативно.
Сложные типы: Когда вы взаимодействуете со сложным типом, вы работаете со ссылкой на его значение.
object
array
function
Какие типы в JS изменяемые, а какие нет?
Типы данных в языке JavaScript можно разделить на простые и объектные. Их также можно разделить на типы с методами и типы без методов. Кроме того, типы можно характеризовать как изменяемые и неизменяемые.
Значение изменяемого типа можно изменить. Объекты и массивы относятся к изменяемым типам: программа на языке JavaScript может изменять значения свойств объектов и элементов массивов.
Числа, логические значения,null
иundefined
являются неизменяемыми - не имеет даже смысла говорить об изменчивости, например, значения числа. Строки можно представить себе как массивы символов, отчего можно счесть, что они являются изменяемыми. Однако строки в JavaScript являются неизменяемыми: строки предусматривают возможность обращения к символам по числовым индексам, но в JavaScript отсутствует возможность изменить существующую текстовую строку.
Все простые типы неизменяемы.
// изменим имя объекта
obj.name = "star";
array[1] = 325; console.log(array); // Array [ 1, 325, 3 ]
// мы не можем изменить строку.
var myString = "Some string";
console.log(myString.toUpperCase()); // SOME STRING. Это уже новая строка.
console.log(myString); // выведем строку еще раз и убедимся, что она не изменилась.
Что значит ссылка на переменную?
https://learn.javascript.ru/object
Что такое NaN
? Как проверить, что переменная - NaN
?
NaN
? Как проверить, что переменная - NaN
?Тем не менее, обратите внимание на разницу между функцией isNaN()
и методом Number.isNaN()
: первая вернет true
, если значение в настоящий момент является NaN
, или если оно станет NaN
после того, как преобразуется в число, в то время как последний вернет true
, только если текущим значением является NaN
:
Что значит создавать переменную через конструктор или через литерал?
Переменные можно объявить как по простому (литерально) (var a = ‘str’), так и через функцию-конструктор (обёртка)(var a = new String(‘str’)). Во втором случае мы получим уже не примитив, а объект созданный конструктором String().
Конструкторы следует вызывать при помощи оператора new
. Такой вызов создаёт пустой this
в начале выполнения и возвращает заполненный в конце.
Когда при обращении к свойству объекта стоит использовать точечную нотацию, а когда через строку в квадратных скобках?
Что произойдет, если попытаться получить несуществующее в объекте свойство?
При доступе к несуществующему свойству объекта JavaScript возвращает undefined
.
Обратите внимание на пример:
favoriteMovie
— это объект с одним значением title
. Доступ к несуществующему свойству actors
путём использования favoriteMovie.actors
приведет к выводу undefined
.
Сам по себе доступ к несуществующему свойству не вызывает ошибки. Реальная проблема возникает при попытке получить значение из undefined
.
Немного изменим предыдущий фрагмент кода, чтобы пояснить поведение TypeError
:
В favoriteMovie
нет свойства actors
, поэтому использование favoriteMovie.actors
приведет к undefined
.
В результате доступ к элементу со значением undefined
с помощью выражения favoriteMovie.actors [0]
вызывает TypeError
.
Возможности JavaScript, которые позволяют получить доступ к несуществующим свойствам, являются источником путаницы. Свойство может быть установлено или может отсутствовать. Идеальным решением этой проблемы будет установка правил для объекта, которые позволят ему содержать только свойства с явно заданными значениями.
Что делает hasOwnProperty
?
hasOwnProperty
?obj.hasOwnProperty('prop')
проверяет объект на наличие собственного свойства;'prop' in obj
проверяет объект на наличие собственного или унаследованного свойства.
Рекомендацией в этом случае будет использование оператора in
. У него простой и понятный синтаксис. Присутствие оператора in
указывает на четкое намерение проверить, имеет ли объект определенное свойство, не обращаясь к фактическому значению этого свойства.
Использование obj.hasOwnProperty('prop')
— это также неплохое решение. Оно немного длиннее, чем оператор in
, и проверяет только собственные свойства объекта.
NULL VS UNDEFINED
typeof(null) - object
typeof(undefined) - undefined
оба примитивные типы
if(null) = if(undefined) => false always
null - пустота; indefined - отстуствие
null нужно объявлять всегда явно; undefined можем быть переменная без присвоения ей undefined (можем и явно, и неявно объявлять)
Когда использовать null
, а когда undefined
?
null
, а когда undefined
?В первую очередь null
отличается своим применением, и в отличие от undefined
, null
больше используется для присваивания значения. Как раз из-за этого оператор typeof
для null
возвращает «object». Изначально это объяснялось тем, что null
использовался (и используется) как пустая ссылка там, где ожидается объект, что-то вроде заглушки. Такое поведение typeof
было позже признано багом, и, хотя было предложено это поведение исправить, пока что, в целях обратной совместимости, всё остается как есть.
Вот, почему окружение JavaScript не выставляет никаких значений в null
, и это делается только программно. В документации на MDN написано следующее:
В различных API
null
часто возвращается в тех местах, где ожидается объект, но такой объект подобрать нельзя.
Это правдиво для DOM, который не зависит от языка и никак не описывается в документации ECMAScript. Из-за того, что используется внешний API, попытка получить отсутствующий элемент возвращает null
, а не undefined
.
Вообще, если нужно присвоить «не-значение» переменной или свойству, передать его в функцию, или вернуть из функции, то null
— это почти всегда лучший вариант. Упрощённо: JavaScript использует undefined
, а программисты должны использовать null
.
Другой способ применения null
— явное «зануливание» переменной (object = null
), когда ссылка на объект больше не требуется. Кстати, это считается хорошей практикой. Присваивая null
, вы фактически удаляете ссылку на объект, и если на него нет других ссылок, он отправляется к сборщику мусора, таким образом возвращая доступную память.
Какие есть способы создания глобальных переменных?
Все переменные, которые объявлены вне функций, являются глобальными.
Необъявленные переменные. Если мы не используем ключевое слово при определении переменной в функции, то такая переменная будет глобальной.
Для чего нужна директива use strict
?
use strict
? Определение глобальных переменных в функциях может вести к потенциальным ошибкам. Чтобы их избежать используется строгий режим или strict mode
:
В этом случае мы получим ошибку SyntaxError: Unexpected identifier
, которая говорит о том, что переменная foo не определена.
Строгий режим изменяет и синтаксис, и поведение кода во время выполнения. Наиболее важные изменения:
преобразование ранее допустимых ошибок в ошибки синтаксиса или ошибки выполнения;
изменения, упрощающие вычисление конкретных переменных;
изменения, упрощающие функцию
eval
и объектarguments
;изменения, которые будут применены в будущей спецификации ES;
улучшение производительности.
Он также исправляет ошибки, мешающие движкам JavaScript производить оптимизацию, и запрещает функции, которые могут быть определены в будущих версиях JavaScript.
Выражения
Что такое выражения и инструкции? В чем отличия между ними?
Выражение — это фрагмент кода, который превращается в значение. Другими словами — становится значением. Да, знаю, 5
— это уже значение, но для интерпретатора JavaScript это выражение, которое превращается в значение 5
. Другое выражение, которое превращается в значение 5
— это, например, 2 + 3
.
Вызов функции getAnswer()
— это тоже выражение, потому что функция что-то возвращает. Этот вызов будет заменён на значение, которое она возвращает. Другими словами, вызов функции превратится в значение, а поэтому он является выражением.
Выражения делятся на простые (их также называют первичными) и сложные. Простые выражения являются самостоятельными выражениями, они не включают в себя ещё более простых выражений. К простым выражениям относятся: ключевое слово this
, идентификаторы и литералы. Сложные выражения состоят из простых выражений. Типичный способ конструирования сложных выражений из простых выражений заключается в использовании операторов:
JavaScript различает выражения и инструкции. Инструкция — это команда, действие. Помните условие с if
, циклы с while
и for
— всё это — инструкции, потому что они только производят и контролируют действия, но не становятся значениями.
Инструкция – это указание на совершение какого-либо действия, например, создать переменную, запустить цикл, выполнить условную инструкцию, выйти из функции и т. п. Любая программа представляет собой последовательность выполняемых инструкций. Окончание инструкции обозначается символом ;
(точка с запятой):
Составная инструкция – это просто последовательность из нуля и более инструкций, заключённая в фигурные скобки. Отдельные инструкции внутри составной инструкции надо завершать точками с запятой, но саму составную инструкцию завершать точкой с запятой не нужно:
Чем отличаются var
, let
, const
? Почему использование const
может быть предпочтительнее?
var
, let
, const
? Почему использование const
может быть предпочтительнее?Теперь главный вопрос: что следует использовать var
, let
, или const
? Наиболее популярное мнение, под которым подписываюсь и я, — всегда использовать const
, кроме тех случаев, когда вы знаете, что переменная будет изменятся. Используя const
, вы как бы говорите себе будущему и другим разработчикам, которые будут читать ваш код, что эту переменную изменять не следует. Если вам нужна изменяемая переменная (например, в цикле for
), то используйте let
.
Таким образом, между изменяемыми и неизменяемыми переменными осталось не так много различий. Это означает, что вам больше не придётся использовать var
.
Что такое тернарный оператор?
Условный (тернарный) оператор - единственный оператор в JavaScript, принимающий три операнда: условие, за которым следует знак вопроса (?), затем выражение, которое выполняется, если условие истинно, сопровождается двоеточием (:), и, наконец, выражение для выполнить, если условие ложно. Он часто используется в качестве укороченного варианта условного оператора if
.
При присвоении значения также возможно выполнение более одной операции. В этом случае переменной будет присвоено то значение, которое стоит последним в списке значений, разделенных запятой.
Что делает оператор for..in
? Какие имеются особенности при использовании этого оператора с массивами?
for..in
? Какие имеются особенности при использовании этого оператора с массивами? Цикл for...in
проходит только по перечисляемым свойствам. Объекты, созданные встроенными конструкторами, такими как Array
и Object
имеют неперечисляемые свойства от Object.prototype
и String.prototype
, например, от String
-это indexOf()
, а от Object
- метод toString()
. Цикл пройдёт по всем перечисляемым свойствам объекта, а также тем, что он унаследует от конструктора прототипа (свойства объекта в цепи прототипа).
Упорядочение свойство объекта. Короткий ответ: свойства упорядочены особым образом: свойства с целочисленными ключами сортируются по возрастанию, остальные располагаются в порядке создания. Разберёмся подробнее.
Замечание: for...in
не следует использовать для Array
, где важен порядок индексов.
Индексы массива - это перечисляемые свойства с целочисленными именами, в остальном они аналогичны свойствам объектов. Нет гарантии, что for...in
будет возвращать индексы в конкретном порядке. Цикл for...in
возвращает все перечисляемые свойства, включая имеющие нецелочислиненные имена и наследуемые.
Это – плохая идея. Существуют скрытые недостатки этого способа:
Цикл
for..in
выполняет перебор всех свойств объекта, а не только цифровых.В браузере и других программных средах также существуют так называемые «псевдомассивы» – объекты, которые выглядят, как массив. То есть, у них есть свойство
length
и индексы, но они также могут иметь дополнительные нечисловые свойства и методы, которые нам обычно не нужны. Тем не менее, циклfor..in
выведет и их. Поэтому, если нам приходится иметь дело с объектами, похожими на массив, такие «лишние» свойства могут стать проблемой.Цикл
for..in
оптимизирован под произвольные объекты, не массивы, и поэтому в 10-100 раз медленнее. Увеличение скорости выполнения может иметь значение только при возникновении узких мест. Но мы всё же должны представлять разницу.
Так как порядок прохода зависит от реализации, проход по массиву может не произойти в правильном порядке. Следовательно лучше с числовыми индексами использовать циклы for
, Array.prototype.forEach()
или for...of
, когда проходим по массивам, где важен порядок доступа к свойствам.
Как безопасно проверить, что переменная существует (была объявлена), и не словить ReferenceError?
Ответ:
About "void(0)":
Подробнее:
В JavaScript null
- это объект. Есть еще одно значение для вещей, которые не существуют, undefined
. DOM возвращает null
почти во всех случаях, когда не удается найти какую-либо структуру в документе, но в самом JavaScript не undefined
используемое значение.
Во-вторых, нет, прямого эквивалента нет. Если вы действительно хотите проверить на наличие null
, выполните:
Если вы хотите проверить, существует ли переменная, это можно сделать только с помощью try
/catch
, поскольку typeof
будет обрабатывать необъявленную переменную и переменную, объявленную со значением undefined
как эквивалентную.
Но, чтобы проверить, объявлена ли переменная и не undefined
:
Если вы знаете, что переменная существует, и хотите проверить, есть ли в ней какое-либо значение:
Если вы хотите знать, существует ли член независимо, но не волнует его значение:
Если вы хотите узнать, является ли переменная истинной:
Массивы
Способы создания массивов (литерал, конструктор, фабричные методы Array.from()
и Array.of()
);
Array.from()
и Array.of()
);Удаление элемента из массива (какие есть способы и в чем особенности);
arr.pop()
– извлекает элемент из концаarr.shift()
– извлекает элемент из началаdelete(длина не меняется, если не юзать delete obj.key):
arr.splice:
arr.slice:
_reject (lodash)
filter:
Свойство length
у массива
length
у массиваКакое значение будет у свойства
length
массиваa
и почему:Что будет, если переприсвоить новое значение?
Влияет ли на
length
удаление элемента посередине массива? Какие способы удаления элементов влияют на длину, а какие нет?
Как проверить, что в переменной лежит массив?
variable instanceof Array
Array.isArray(variable)
This is the fastest method on Chrome, and most likely all other browsers. All arrays are objects, so checking the constructor property is a fast process for JavaScript engines.
If you are having issues with finding out if an objects property is an array, you must first check if the property is there.
Что делают, как и когда использовать следующие методы:
reduce
для прохода по массиву с вычислением значения.
sort
Метод sort()
на месте сортирует элементы массива и возвращает отсортированный массив. Сортировка не обязательно устойчива (англ.). Порядок cортировки по умолчанию соответствует порядку кодовых точек Unicode.
filter
map
НЕ мутирует массив, создает новый
forEach
Мутирует массив.
some
Метод some()
проверяет, удовлетворяет ли какой-либо элемент массива условию, заданному в передаваемой функции.
метод возвращает false
при любом условии для пустого массива.
every
Метод every()
проверяет, удовлетворяют ли все элементы массива условию, заданному в передаваемой функции.
Hash Tables(map). Ассоциативные массивы.
Ассоциативный массив — абстрактный тип данных, с помощью которого хранятся пары ключ-значение. У него есть и другие названия: "словарь", "мап" (от слова map).
Ассоциативный массив, в отличие от обычного массива (называемого индексированным, так как значения в нем расположены по индексам), нельзя положить в память "как есть". У него нет индексов, которые бы могли определить порядок и простой способ добраться до значений. Для реализации ассоциативных массивов часто используют специальную структуру данных — хеш-таблицу. Она позволяет организовать данные ассоциативного массива удобным для хранения способом. Для этого хеш-таблица использует две вещи: индексированный массив и функцию для хеширования ключей.
Хеширование
Любая операция внутри хеш-таблицы начинается с того, что ключ каким-то образом преобразуется в индекс обычного массива. Для получения индекса из ключа, нужно выполнить два действия: найти хеш (хешировать ключ) и привести его к индексу (например через остаток от деления).
Хеширование — операция, которая преобразует любые входные данные в строку (реже число) фиксированной длины. Функция, реализующая алгоритм преобразования, называется "хеш-функцией", а результат называют "хешем" или "хеш-суммой". Наиболее известны CRC32, MD5 и SHA (много разновидностей).
С хешированием мы встречаемся в разработке часто. Например, идентификатор коммита в git 0481e0692e2501192d67d7da506c6e70ba41e913
не что иное, как хеш, полученный в результате хеширования данных коммита.
После того как хеш получен, его можно преобразовать в индекс массива, например, через получение остатка от деления:
Ассоциативный массив в JavaScript представлен типом данных Object.
Функции
В JavaScript функции — это объекты. Поэтому функции могут принимать другие функции в качестве аргументов, а также функции могут возвращать функции в качестве результата. Функции, которые это умеют, называются функциями высшего порядка. А любая функция, которая передается как аргумент, называется callback-функцией (также это передача контроля другой функции).
Какие есть 4 шаблона вызова функции, которые задают контекст выполнения этой функции?
Оператор вызова — круглые скобки (), которые могу заключать в себе параметры, разделенные через запятую. К сожалению, существует несколько паттернов для вызова функций. Нужно понять, потому как, в зависимости от выбранного паттерна, вы получите разные результаты.
Оператор для вызова функции один, а способов вызова — четыре. Итак, существует четыре пути вызова функций:
Вызов метода — Method Invocation
Вызов функции — Function Invocation
Вызов конструктора — Constructor Invocation
Вызов apply и call — Apply And Call Invocation
Вызов метода — Method Invocation Когда функция является частью объекта, она называется методом. «Вызов метода» представляет из себя вызов функции, принадлежащей объекту. Пример:
В «вызове метода» значение this
будет ссылаться на объект, которому принадлежит функция, в нашем случае на obj, причем данная связь будет установлена после запуска функции, что носит термин позднего привязывания (late binding).
Вызов функции — Function Invocation Вызов функции выполняется с помощью оператора ():
add(2,3); //5
Используя данный паттерн, this
привязывается к global object. Это, несомненно, является ошибкой языка — постоянная привязка this к глобальному объекту может уничтожить его контекст. Это особенно заметно, если использовать функцию внутри метода. Давайте посмотрим на пример:
Обратите внимание, innerFunction
вызывается с использованием вышеупомянутого паттерна «вызова функции», соответственно this
привязывается к global object. В результате мы и получаем 500.
Можно легко обойти эту проблему путем создания переменной this
, но это, по моему мнению, является хаком.
Вызов конструктора — Constructor Invocation
В классическом ООП объект является реализацией класса. В С++ и Java для такой реализации используется оператор new
. Судя по всему, создатели JS решили не ходить далеко за примером, и реализовать нечто подобное в паттерне «вызов конструктора»…
Паттерн запускается путем размещения оператора new
прямо перед вызовом, например:
Несмотря на то, что Cheese
является функциональным объектом (а значит умеет переваривать код), мы создали новый объект путем вызова функции с new
. this
в данном случае будет относиться к свежесозданному объекту, и поведение return
будет изменено. К слову о return. Его использования в «вызове конструктора» имеет две особенности:
если функция возвращает число, цепочку, логическое выражение (true/false), null или undefined,
return
не сработает, a мы получимthis
если функция возвращает реализацию объекта (то есть все, кроме простых переменных), мы увидим данный объект, а не
this
Вызов apply и call — Apply And Call Invocation
Этот паттерн продуман гораздо лучше остальных. Он позволяет вручную запустить функцию, попутно снабдив ее параметрами и обозначив this
. Из-за того, что функции у нас являются полноправными объектами, каждая функция в JavaScript связана с Function.prototype, а значит мы можем легко добавлять к ним методы.
Данный паттерн использует два параметра: первый — это объект, к которому привязывается this
, второй — это массив, связанный с параметрами:
В примере выше this
относится к null
(функция не является объектом), а массив привязан к num1
и num2
. Но продолжим эксперементировать с первым параметром:
Этот пример использует apply
для привязки this
к obj
. В результате мы в состоянии получить значение this.data
. Настоящая ценность apply заключается именно в привязывании this
.
В JavaScript также существует оператор call
, похожий на apply
всем, за исключением того что получает не параметры, а список аргументов.
Как директива use strict
влияет на this
внутри функции?
use strict
влияет на this
внутри функции?В функциях как f()
, значением this
является глобальный объект. В строгом режиме он теперь равен undefined
. Когда функция вызывалась с помощью call
или apply
, если значением был примитив, он упаковывался в соответствующий объект (или в глобальный объект для undefined
и null
). В строгом режиме значение передается без каких-либо преобразований и замен. Используйте this
только тогда, когда он ссылается на объект, созданный вами.
Какой наиболее простой паттерн, позволяющий облегчить читаемость функции, когда у нее огромное количество аргументов?
Вызов функции — Function Invocation
Как получить все аргументы функции (включая те, что не объявлены, но все-таки были переданы)?
Что такое рекурсия? Когда удобно её использовать?
Рекурсия – это приём программирования, полезный в ситуациях, когда задача может быть естественно разделена на несколько аналогичных, но более простых задач. Или когда задача может быть упрощена до несложных действий плюс простой вариант той же задачи. Их суть состоит в том, что функция вызывает саму себя.
Итак, рекурсию используют, когда вычисление функции можно свести к её более простому вызову, а его – к ещё более простому и так далее, пока значение не станет очевидно.
Максимальная глубина рекурсии ограничена движком JavaScript. Точно можно рассчитывать на 10000 вложенных вызовов, некоторые интерпретаторы допускают и больше, но для большинства из них 100000 вызовов – за пределами возможностей.
Любая рекурсия может быть переделана в цикл. Как правило, вариант с циклом будет эффективнее.
Но переделка рекурсии в цикл может быть нетривиальной, особенно когда в функции в зависимости от условий используются различные рекурсивные подвызовы, результаты которых объединяются, или когда ветвление более сложное. Оптимизация может быть ненужной и совершенно не стоящей усилий.
Часто код с использованием рекурсии более короткий, лёгкий для понимания и поддержки. Оптимизация требуется не везде, как правило, нам важен хороший код, поэтому она и используется.
Что такое замыкания, и в каких случаях они могут быть полезны? Как сохранить состояние с помощью замыкания, и для чего это состояние может быть использовано?
Замыкание это функция у которой есть доступ к своей внешней функции по области видимости, даже после того, как внешняя функция прекратилась. Это говорит о том, что замыкание может запоминать и получать доступ к переменным, и аргументам своей внешней функции, даже после того, как та прекратит выполнение.
Замыкания подобны объектам в том смысле, что они представляют собой механизм для хранения состояния:
Как реализовать функцию bind
?
bind
? Метод bind()
создаёт новую функцию, которая при вызове устанавливает в качестве контекста выполнения this
предоставленное значение. В метод также передаётся набор аргументов, которые будут установлены перед переданными в привязанную функцию аргументами при её вызове.
Методы apply()
и call()
практически идентичны при работе с выставлением значения this
, за исключением того, что вы передаёте параметры функции в apply()
как массив, в то время, как в call()
, параметры передаются в индивидуальном порядке. Но дальше ещё интереснее.
Решить такую вот проблему: пускай у нас есть массив ссылок, и наша задача — сделать так, чтобы при клике на каждую выводился alert
ом ее порядковый номер. Первое решение, что приходит в голову, выглядит так:
alert
ом ее порядковый номер. Первое решение, что приходит в голову, выглядит так:На деле же оказывается, что при клике на любую ссылку выводится одно и то же число — значение links.length
. Почему так происходит и как эту гадость исправить?
Ответ: В связи с замыканием объявленная вспомогательная переменная i продолжает существовать, при чем и в тот момент, когда мы кликаем по ссылке. Поскольку к тому времени цикл уже прошел, i остается равным кол-ву ссылок - это значение мы и видим при кликах.
Решается эта проблема следующим образом:
Здесь с помощью еще одного замыкания мы «затеняем» переменную i, создавая ее копию в его локальной области видимости на каждом шаге цикла. Благодаря этому все теперь работает как задумывалось.
Что такое callback (функция обратного вызова)? Когда они обычно применяются?
Функция обратного вызова - это функция, переданная в другую функцию в качестве аргумента, которая затем вызывается по завершению какого-либо действия.
Выше приведен пример синхронного обратного вызова, поскольку функция processUserInput
выполняется синхронно.
Функции обратного вызова часто используются для продолжения выполнения кода после завершения асинхронной операции - они называются асинхронными обратными вызовами.
Что такое каррирование?
Каррирование или карринг (currying) в функциональном программирование — это преобразование функции с множеством аргументов в набор вложенных функций с одним аргументом. При вызове каррированной функции с передачей ей одного аргумента, она возвращает новую функцию, которая ожидает поступления следующего аргумента. Новые функции, ожидающие следующего аргумента, возвращаются при каждом вызове каррированной функции — до тех пор, пока функция не получит все необходимые ей аргументы. Ранее полученные аргументы, благодаря механизму замыканий, ждут того момента, когда функция получит всё, что ей нужно для выполнения вычислений. После получения последнего аргумента функция выполняет вычисления и возвращает результат.
Что такое частичное применение функций?
Возникает ощущение, что количество вложенных функций, при представлении функции в виде набора вложенных функций, зависит от количества аргументов функции. И, если речь идёт о каррировании, то это так.
Каррирование и частичное применение функций очень похожи друг на друга, но концепции это разные.
При частичном применении функцию преобразуют в другую функцию, обладающую меньшим числом аргументов (меньшей арностью). Некоторые аргументы такой функции оказываются зафиксированными (для них задаются значения по умолчанию).
Как видите, при каррировании число вложенных функций равно числу аргументов исходной функции. Каждая из этих функций ожидает собственный аргумент. При этом понятно, что если функция аргументов не принимает, или принимает лишь один аргумент, то каррировать её нельзя.
Что такое мемоизация?
Очевидно, что цель мемоизации — сокращение времени и количества ресурсов, потребляемых при исполнении «дорогостоящих вызовы функций».
Мемоизация использует кеширование для хранения результатов наших вызовов для быстрого и легкого доступа в более позднее время.
Кеш — это просто временное хранилище данных.
В первый раз она делает необходимые вычисления и «запоминает» результат, сохраняя его в кеше. Если в будущем она получит те же самые входные данные, то не будет вычислять повторно, а просто возьмет ответ из памяти (кеша).
Идея мемоизации в JavaScript основывается на двух концепциях:
замыканиях
и функциях высшего порядка — функциях, которые возвращают другие функции.
Прототипы
Что такое функция-конструктор? Как их создавать и как ими пользоваться?
Функции-конструкторы являются обычными функциями. Но есть два соглашения:
Имя функции-конструктора должно начинаться с большой буквы.
Функция-конструктор должна вызываться при помощи оператора
"new"
.
Когда функция вызывается как new User(...)
, происходит следующее:
Создаётся новый пустой объект, и он присваивается
this
.Выполняется код функции. Обычно он модифицирует
this
, добавляет туда новые свойства.Возвращается значение
this
.
Другими словами, вызов new User(...)
делает примерно вот что:
То есть, результат вызова new User("Вася")
– это тот же объект, что и:
Используя специальное свойство new.target
внутри функции, мы можем проверить, вызвана ли функция при помощи оператора new
или без него.
В случае, если функция вызвана при помощи new
, то в new.target
будет сама функция, в противном случае undefined
.
Обычно конструкторы ничего не возвращают явно. Их задача – записать все необходимое в this
, который в итоге станет результатом.
Но если return
всё же есть, то применяется простое правило:
При вызове
return
с объектом, будет возвращён объект, а неthis
.При вызове
return
с примитивным значением, примитивное значение будет отброшено.
Другими словами, return
с объектом возвращает объект, в любом другом случае конструктор вернёт this
.
В примере ниже return
возвращает объект вместо this
:
А вот пример с пустым return
(или мы могли бы поставить примитив после return
, неважно)
В this
мы можем добавлять не только свойства, но и методы.
Например, в примере ниже, new User(name)
создаёт объект с данным именем name
и методом sayHi
:
Что такое прототип? Какие возможности имеет/дает?
Почему методы объекта лучше хранить в прототипе, а не в самом объекте?
It’s neat and definitely saves on resources!
Можно ли создать инстанс функции через конструктор? И если да, то как, а если нет, то какой бы интерфейс вы реализовали бы для этой задачи?
Function
constructor создает новый объект Function
. Вызов constructor
создает функцию динамически, но страдает от проблем безопасности и аналогичных (но гораздо менее значительных) проблем производительности eval
. Однако, в отличие от eval, конструктор функций создает функции, которые выполняются только в глобальной области..
Примечание: функции, созданные конструктором Function
, не создают замыканий на их контексты создания; они всегда создаются в глобальной области видимости. При их вызове, они получат доступ только к своим локальным переменным и переменным из глобальной области видимости, но не к переменным в той области видимости, в которой вызывался конструктор Function
. Это поведение отличается от поведения при использовании функции eval
с кодом создания функции.
Как создать объект, который ни от чего не наследуется?
Очень просто сказано, new X
есть Object.create(X.prototype)
с дополнительным запуском функции constructor
.
Чтобы создать объект, не имеющий прототипа, можно передать значение null, но в этом случае вновь созданный объект не унаследует ни каких-либо свойств, ни базовых методов, таких как toString() (а это означает, что этот объект нельзя будет использовать в выражениях с оператором +):
Какие 3 (как минимум) способа есть отнаследоваться в JavaScript-е? В чем отличия и нюансы?
Как в переопределенном методе у наследующего класса вызвать переопределяемый метод родительского? Пример псевдокода:
Какие есть способы навсегда привязать метод класса к его инстансу (чтобы this
всегда был текущим экземпляром класса)?
this
всегда был текущим экземпляром класса)?Last updated
Was this helpful?