JS Basics Flashcards
Brush up your knowledge of the basic concepts
Какие типы данных есть в JavaScript?
Number
BigInt
String
Boolean
Null
Undefined
Object
Symbol
Как в JavaScript хранятся числа? Какие ошибки могут возникать при их использовании?
Числа хранятся в 64 битном формате, с плавающей точкой двойной точности.
Ошибки могут возникать при записи дробей. Так как не все дроби удобно представимы в двоичной системе, у них может возникать мантисса (её можно отбрасывать при помощи округления).
Чем отличается null от undefined?
Undefined - это внутренняя переменная языка, которая показывает что мы пытаемся получить несуществующий объект.
Null - это ключевое слово, которым пользователь создаёт заглушку, чтобы показать отсутствие требуемого результата выполнения части программы.
Чем отличаются function declaration и function expression?
Function declaration всегда создаёт именованную функцию. Такая функция всплывает - она может быть использована до объявления.
Function expression создаёт анонимную функцию, которая может быть немедленно присвоена в переменную, вызвана или передана в другую функцию. Эти функции создаются только когда исполнение кода доходит до них.
Чему равен this у функции?
Если функция вызывается из объекта, то this ссылается на этот объект.
Если функция не принадлежит объекту, то this будет undefined в строгом режиме или будет ссылаться на глобальный объект (window в браузере) в обычном режиме.
Также this может быть потерян если мы передадим метод объекта в другую функцию вне объекта. Также this может быть явно указан в методах call и apply.
К какому типу данных относится NaN? Infinite? Где они определены?
Оба - числовой тип. NaN показывает число, которое нельзя представить в виде числа. Infinite нужен для представления результатов вычислений результатом которых является бесконесность.
И NaN, и Infinity - это неперезаписываемые переменные глобального контекста.
Что выведет typeof null?
Object
Что выведет typeof []? Почему?
Object
Массив - это объект со специальными свойствами (length, Symbol.Iterator) и прототипом Array в котором есть специальные методы массивов.
В каких случаях происходит неявное преобразование к числу?
- Операторы сравнения (>, =, <=);
- Побитовые операторы (|, &, ^, ~);
- Унарный +;
- Арифметических операции (+, -, *, /), кроме “+” где хоть один операнд - строка.
- Нестрогое равенство “==” (кроме случаев, когда оба операнда - строки, когда один из операндов null или undefined);
Как строка преобразуется к числу?
- Убираются пробелы, переносы строки и табы
- Если результат - пустая строка -> 0
- Если результат непустой, то результат будет или число, или NaN если число нельзя считать
Как Null, Undefined и Symbol преобразуются к числу?
null -> 0
undefined -> NaN
Symbol -> TypeError
Чему равен (==) NaN?
Ничему, даже самому себе
Чему равен (==) undefined?
undefined, null
Чему равен (==) null?
null, undefined
В каких случаях происходит неявное преобразование к строке?
- Бинарный “+”, когда один из операндов - строка
- В случаях, когда по контексту нужно преобразование к строке: console.log(), alert(), и тд. ( неявный вызов toString() )
Как символьный тип приводится к строке?
Приводится только явно:
String(Symbol(‘my symbol’)) // ‘Symbol(my symbol)’
Неявное приведение вызывает ошибку:
‘ ‘ + Symbol(‘my symbol’) // TypeError is thrown
В каких случаях происходит неявное преобразование к булевому типу данных?
- Логический контекст (в условии оператора if).
2. С логическими операторами (||, &&, !)
Какие значения в JS приводятся к false? (falsy values)
- Boolean(‘’) // false
- Boolean(0) // false
- Boolean(-0) // false
- Boolean(NaN) // false
- Boolean(null) // false
- Boolean(undefined) // false
Как объекты приводятся к примитивам?
Приведение к Boolean - всегда true.
Для определения, к какому типу нужно приводить объект, javascript использует хинты ‘string’, ‘number’ и ‘default’.
Сначала вызывается objSymbol.toPrimitive, если он не существует и хинт - строка, то вызывается сначала obj.toString() а затем, если вызов ничего не вернул, вызывается obj.valueOf(). Если хинт - число или дефолтный, интерпретатор пытается вызвать эти методы в обратном порядке.
Как можно осуществить проверку на undefined?
if( x === undefined) {}
if( typeof x === ‘undefined’ ) {}
Последний метод не выбрасывает исключение если переменная х не была объявлена. Но на практике это используется редко.
Какие особенности у ключевого слова var?
- Область видимости var ограничена только функциями и модулями (не имеют блочной области видимости).
- Переменные var инициализируются сразу при начале выполнения функции/скрипта (всплытие).
- Переменную с var можно объявить несколько раз.
Почему лучше никогда не использовать конструкторы Number, String, Boolean с оператором new?
Потому что в таком случае будет создан не примитив, а объект. Это ведёт к непредсказуемому и плохо читаемому коду. Пример:
a = new Number(0) if (a) {console.log("error!") // выведет error! потому что a - это объект
Является ли такая запись перевода числа 123456 в двоичную систему корректной?
123456..toString(2)
Да, является. Первая точка после числа показывает интерпретатору, что это конец целой части, а вторая точка нужна уже для вызова метода.
Какое максимальное число может хранить JS? Что он вернёт если мы попытаемся записать число больше этого предела (например, 2е500)?
2^52 – 64 бит: 52 бит для цифр, 11 бит для положения точки и 1 бит для знака.
Вернёт infinity.
Как кодируются строки? Что такое суррогатные пары и как реализуются диакритические знаки?
Используется кодировка UTF-16 – символы кодируются 16-битными словами. Этого хватает для большинства символов, остальные же (например, эмоджи) кодируются двумя словами - такие символы называют суррогатными парами.
Диакритические знаки можно реализовать если добавить коды символов (верхняя точка, нижний апостроф, …) после самого символа.
Как происходит сравнение строк (операторы >, =, <=) в JS?
Сравнение проводится в лексикографическом порядке, то есть, посимвольно. Значение каждого символа определяется его номером в таблице юникод. Например, z > Z даст true потому что 122 > 90.
Как в js реализованы массивы?
Массивы - это объекты с числовыми индексами, специальными методами и свойством length.
JS оптимизирует объекты-массивы - он старается хранить их в непрерывной области памяти, что существенно ускоряет произвольный доступ к элементам массива. Однако оптимизации не работают, если работать с массивом как с обычным объектом.
В чём главная проблема использования for..in при обходе массивов?
Этот способ в 10-100 раз медленнее чем for..of, потому что заточен для обхода любых объектов.
Если у массива попытаться перезаписать свойство lenght, к чему это приведёт?
Если новое значение больше старого, ничего не изменится. Если новое значение будет меньше старого, то число элементов в массиве уменьшится.
Как массив приводится к примитивным типам?
Так как это объект, то boolean – всегда будет true.
Так как у массивов нет Symbol.toPrimitive и valueOf, то они всегда будут приводиться к строке.
Результат приведения - элементы, разделённые запятой.
Что возвращает метод splice у массивов?
Он возвращает удалённые элнменты
Может ли метод splice вставить новые элементы в массив?
Да, splice вставит все аргументы, начиная с третьего
Чем slice отличается от splice в массивах?
- Slice - возвращает копию, splice - проводит манипуляции в самом массиве.
- Разные аргументы:
slice([start], [end]),
splice(start[, deleteCount, arg1, …, argN])
Какие вы знаете методы удаления/вставки/объединения массивов?
slice ([start], [end])
splice (start[, deleteCount, arg1, …, argN])
concat (arg1, …, argN)
[…arr1, …arr2, etc.]
Какие вы знаете методы поиска в массивах?
Методы со строгим сравнением “===”
indexOf(item, from)
lastIndexOf(item, from)
includes(item, from)
Методы со своей функцией сравнения
find( function(item, index, array) {…} ) // вернёт элемент или undefined
findIndex // вернёт индекс или -1
filter( function( item, index, array) {…} ) // вернёт массив элементов
Какие вы знаете методы преобразования массивов?
С заменой текущего массива: *sort ( function compare(a, b) { if (a > b) return >0; if (a == b) return 0; if (a < b) return <0; } ) // без колбэка - преобразует к строкам и сравнит их через === *reverse() *join(glue) / split(delimiter)
С копированием в новый массив
- filter( function( item, index, array) {…} )
- map( function( item, index, array) {…} )
- reduce( function( acc, item, index, array) {…} )
Какие вы знаете методы для преобразования массивов?
С заменой текущего массива: *sort ( function compare(a, b) { if (a > b) return >0; if (a == b) return 0; if (a < b) return <0; } ) // без колбэка - преобразует к строкам и сравнит их через === *reverse() *join(glue) / split(delimiter)
С копированием в новый массив
- filter( function( item, index, array) {…} )
- map( function( item, index, array) {…} )
- reduce( function( acc, item, index, array) {…} )
Чем Map принципиально отличается от объекта?
В map ключи могут быть любого типа.
map.length имеет сложность О(1), у объекта она O(n)
Какие методы и свойства есть у map?
set(key, elem) get(key) has(key) delete(key) clear() size
Как можно перебрать map?
- методы
map. keys() // итерируемый объект ключей
map. values() // итерируемый объект значений
map. entries() // итерируемый объект пар [key, value] - цикл for..of
использует map.entries() - forEach ( (value, key, map) => … )
Чем Set принципиально отличается от объекта?
Set - это множество значений без ключей. Значения не повторяются.
Какие основные методы у Set?
add(value) delete(value) has(value) clear() size
В каком порядке происходит перебор map и set?
В порядке добавления
При обходе объекта в цикле, в каком порядке мы получим записи из него?
Сначала мы получим свойства с целочисленными ключами (в порядке возрастания), потом остальные записи в порядке добавления.
При обходе объекта в цикле, в каком порядке мы получим записи из него?
Сначала мы получим свойства с целочисленными ключами (в порядке возрастания), потом остальные записи в порядке добавления.
Целочисленное свойство - это свойство, ключ которого не изменится при преобразовании сначала к целому числу, а затем обратно в строку.
Как можно копировать объект?
Целиком - методы других библиотек вроде _.cloneDeep() или через рекурсивный обход циклом.
Object.assign( {}, obj ) и оператор расширения - поверхностная копия.
Какой принцип лежит в основе управления памятью в Javascript?
Принцип достижимости. Упрощённо, «достижимые» значения – это те, которые доступны или используются. Они гарантированно находятся в памяти.
Любое значение считается достижимым, если оно доступно по ссылке или цепочке ссылок из любого объекта, находящегося в памяти.
Какие можно привести примеры объектов гарантированно находящихся в памяти Javascript?
- Локальные переменные и параметры текущей функции.
- Переменные и параметры других функций в текущей цепочке вложенных вызовов.
- Глобальные переменные.
- (некоторые внутренние значения)
Какой основной алгоритм сборки мусора?
Алгоритм пометок (“Mark-and-sweep”)
Что такое this?
Это ссылка на контекст исполнения функции.
При обычном вызове, this === undefined в строгом режиме или globalObject в обычном.
При вызове функции как метода объекта - через точку - контекстом всегда будет объект до точки.
Что будет, если в функции конструкторе явно вернуть что-то через return?
function Foo() { this.a = 5; return ... ; }
const b = new Foo(); // что тут будет?
Если возвращаем примитив, то он будет проигнорирован и b = { a: 5 }
Если вернуть объект, то в b будет записан именно этот объект.
Можно ли с помощью Object.keys/values/entries или цикла for получить символьные свойства?
Нет, к ним можно только обратиться напрямую.
Заметка: Object.assign() копирует все поля, в том числе и символьные.