Skip to content

Latest commit

 

History

History
276 lines (182 loc) · 10.7 KB

File metadata and controls

276 lines (182 loc) · 10.7 KB

Задачи для практики к собеседованиям на frontend-разработчика - Нюансы языка

Нюансы языка

✅ Задача

Что будет выведено?

0.1 + 0.2 == 0.3
Объяснение

В JS есть числа двойной точности (как double в других языках, 64 разряда) с плавающей точкой, соответствующие стандарту IEEE 754.

У числа есть 2 части:

  • мантисса, или значимая часть, содержит цифры;
  • экспонента указывает, где в мантиссе необходимо расположить десятичную точку;

При такой записи есть проблема с десятичными дробями.
Так, язык JavaScript не может точно представить 0.1, 0.2, 0.3, так как в двоичной системе они являются бесконечными и появляется погрешность.

По итогу, 0.1 + 0.2 == 0.3 выдаст false

0.1.toFixed(20) // '0.10000000000000000555'
0.2.toFixed(20) // '0.20000000000000001110'
0.1 + 0.2       // 0.30000000000000004

✅ Задача

Что будет выведено?

9007199254740991 + 1 === 9007199254740991 + 2 
Решение

9007199254740991 - это значение константы Number.MAX_SAFE_INTEGER. Иными словами – верхний предел диапазона безопасных вычислений, поэтому неважно сколько мы будем прибавлять, в обоих случаях мы упремся в лимит INT.


✅ Задача

Что будет выведено?

Math.sqrt(-1) == Math.sqrt(-1)
Объяснение

Результат Math.sqrt(-1) - NaN (Not a Number). Это специальное значение JavaScript.
В итоге одно значение NaN не равно другому.
А так как NaN нельзя ни с чем сравнивать, то сравнение NaN и NaN будет сравнивать 2 разны значения, поэтому результат будет false.


✅ Задача

Что будет выведено?

Math.max() > Math.min()
Объяснение

Math.max - -Infinite
Math.min - +Infinite

Для Math.min минимальным значением в наборе становится самое большое возможное число, которое меньше или равно каждому члену набора.
В непустом множестве такое число ограничено меньшим из его членов. Но если множество пустое, то для этого числа нет никаких ограничений – и возвращается бесконечность.

В пустом наборе нет члена больше, чем бесконечность, поэтому Math.max() > Math.min() выдаст false.


✅ Задача

Что будет выведено?

['1', '7', '11'].map(parseInt)
Решение

Запись эквивалентна

['1', '7', '11'].map((element, index) => parseInt(element, index))

parseInt используется для перевода значения в систему счисления. Если второй параметр не передан, то используется 10. В нашем случае разрядность передается через index.

Соответстванно

[parseInt('1', 0), parseInt('7', 1), parseInt('11', 2)]

Уметь переводить системы счисления не нужно, этого будет достаточно, но для общего развития, ответ будет таким:

  1. При неопределенном основании взялось дефолтное значение - 10. Результат - 1;
  2. В единичной системе счисления не может быть цифры 7, возвращается NaN.
  3. В двоичной системе число 11 – это 3.

Калькулятор систем счисления


✅ Задача

Что будет выведено?

[] + {} // [object Object]
{} + [] // 0
Обяъснение

В первом выражении вызывается метод массива [].toString, результатом которого будет пустая строка После этого идет сложение и вызывается метод {}.toString, который отдает [object Object]

Во втором выражении {} определяются не как объект, а как блок кода, поэтому он не участвует в сложении Дальше вызывается +[], который переводит [] в числовой вид. Пустой массив в этом случае приводится к 0. Если бы в массиве были значения, вернулась бы 1

[] + {} // [object Object]
{} + [] // 0

✅ Задача

Что будет выведено?

1 < 2 < 3
3 > 2 > 1
Обяъснение

Выражение разбирается слева направо и берет не все выражение целиком, а рассматривает его по частям 1 < 2 = true true < 3 - true приводится к Number и идет сравнение 1 < 3. Результат true.

Во втором варианте 3 > 2 - true true > 1 -> 1 > 1 -> Результат false


✅ Задача

Что будет выведено?

8)
const a = {
  i: 1,
  toString: function () { 
    return a.i++; 
  }
}
a == 1 && a == 2 && a == 3 // ?
Обяъснение

При проверке a вызывается a.toString(). Так как в этом объекте этот методе переопределен, то он возвращает не [object Object], а то, что было написано.

a == 1. Вызываем toString и получаем 1, вызываем ++. Результат true
а == 2. Вызываем toString, i после ++ уже равно 2 - отдаем ее и вызываем ++. Результат true
а == 3. Вызываем toString, i после ++ уже равно 3 - отдаем ее и вызываем ++. Результат true

true && true && true -> true

Ответ: true


Задача

const f0 = () => { console. log(0); return 0 }
const f1 = () => { console. log(1); return 1 }
const f2 = () => { console. log(2); return 2 }
const f3 = () => { console. log(3); return 3 }
const f4 = () => { console. log(4); return 4 }

console.log(f0() || f1() && f2() || f3() && f4())

✅ Задача

var a = {}, b = { key: 'b' }, c = { key: 'c' };

a[b] = c;
a[c] = b;

console.log(a[b]); console.log(a[c]);
Решение

У нас есть 3 переменных: a - путой объект {}
b - объект с полем key = b { key: 'b' }
c - объект с полем key = c { key: 'c' }

На 3 строке используем переменную b как ключ a[b].
При использовании любого типа данных как ключа проихсодить преобразование к типу данных string. При преобразовании объекта к строке происхиодит Object.toString(), который для всех объектов отдаст [object Object].

То есть, на 3 строке происходит обращение a[b], то есть a['[object Object]'].

По этому ключу присваивается объект c и объект a выглядит следующим образом: { '[object Object]': { key: 'c' } }

Дальше идет обращение a[c].
Логика такая же, объект c преобразовывается в строку [object Object] и идет обращение по тому же ключу.
Если обращаемся по тому же ключу, значит перезаписываем значение и итоговая структура будет равна { '[object Object]': { key: 'b' } }

Итого, при обращении к a[b] и a[c] в console.log также будет обращение к одному ключу и будет выведено { key: 'b' } в обоих случаях