Пожалуйста переверните

70 вопросов собеседования JavaScript.

Часть 6.

#translate#javascript

Оригинал статьи 70 JavaScript Interview Questions

51. Что такое async/await и как это работает?

async/await - это новый способ записи асинхронного или неблокируемого кода в JavaScript. Он построен на основе промисов и делает асинхронный код более читаемым и чистым, чем в промисах и функциях обратного вызова (callbacks). Но вам следует изучить промисы перед тем, как пользоваться async/await, потому что, как я уже указал ранее, async/await построен поверх промисов, а это значит, что под капотом все еще используются промисы.

Использование промисов.

unction callApi() {
  return fetch("url/to/api/endpoint")
    .then(resp => resp.json())
    .then(data => {
      // какие то действия с "data"
    }).catch(err => {
      // какие то действия  "err"
    });
}

Использование Async/Await.

Примечание: Мы использовали старое выражение try/catch для перехвата любых ошибок в любой из этих асинхронных операциях внутри блока try.

async function callApi() {
  try {
    const resp = await fetch("url/to/api/endpoint")
    const data = await resp.json()
    // какие то действия с "data"
  } catch (e) {
    // какие то действия с "err"
  }
}

Примечание: Использование ключевого слова async перед function заставляет функцию неявно возращать промис.

const giveMeOne = async () => 1

giveMeOne().then(num => {
  console.log(num) // выводит 1
})

Примечание: Ключевое слово await может быть использовано только внутри функции async. Использование ключевого слова await внутри любой другой функции, не являющейся асинхронной (async function) вызовет ошибку. Ключевое слово await ожидает возврат выражения справа от себя (предположительно промис) перед тем, как следующая линия кода будет исполнена.

const giveMeOne = async () => 1;

function getOne() {
  try {
    const num = await giveMeOne();
    console.log(num);
  } catch (e) {
    console.log(e);
  }
}

// вызовет ошибку Compile-Time Error = Uncaught SyntaxError: await is only valid in an async function

async function getTwo() {
  try {
    const num1 = await giveMeOne(); // заканчивает эту операцию  async перед тем, как передти к
    const num2 = await giveMeOne(); // этой линии
    return num1 + num2;
  } catch (e) {
    console.log(e);
  }
}

await getTwo(); // вернет 2

52. В чем разница между операторами Spread и Rest?

И оператор spread, и rest параметры имеют один и тот же оператор .... Оператор spread расширяет заданный массив или другой итерируемый объект в несколько значений. А параметры Rest используются в функции или массиве, чтобы получить все аргументы или значения из функции или массива и поместить их в массив или извлечь некоторые фрагменты из функции или массива.

function add(a, b) {
  return a + b
}

const nums = [5, 6]
const sum = add(...nums)
console.log(sum)

В примере выше мы используем оператор spread. Когда мы вызываем функцию add, мы раcширяем массив nums. Таким образом, значением параметра a будет 5, а значением b будет 6. Наконец сумма будет равна 11.

function add(...rest) {
  return rest.reduce((total, current) => total + current)
}

console.log(add(1, 2)) // выведет 3
console.log(add(1, 2, 3, 4, 5)) // выведет 15

В примере выше у нас есть функция add, которая принимает любое количество аргументов, добавляет все из них и возвращает итоговое значение.

const [first, ...others] = [1, 2, 3, 4, 5]
console.log(first) // выведет 1
console.log(others) // выведет [2,3,4,5]

А в этом примере мы используем оператор rest для извлечения всех оставшихся элементов массива и помещения их в отдельный массив.

53. Что такое параметры по умолчанию?

Параметры по умолчанию - это новый способ оперделения переменных по умолчанию в JavaScript, который доступен в версии ES6 или ECMAScript 2015.

// ES5
function add(a, b) {
  a = a || 0
  b = b || 0
  return a + b
}

// ES6
function add(a = 0, b = 0) {
  return a + b
}
// Если мы не передадим никаких аргументов для 'a' или 'b' то
// будет использовано значение "параметра по умолчанию" равное 0
add(1) // вернет 1

Мы также можем деструктуризовывать парметры по умолчанию.

function getFirst([first, ...rest] = [0, 1]) {
  return first
}

getFirst() // вернет 0
getFirst([10, 20, 30]) // вернет 10

function getArr({ nums } = { nums: [1, 2, 3, 4] }) {
  return nums
}

getArr() // вернет [1, 2, 3, 4]
getArr({ nums: [5, 4, 3, 2, 1] }) // вернет [5,4,3,2,1]

Мы также можем использовать параметры, определенные ранее, для параметров, отпределенных позднее.

function doSomethingWithValue(
  value = "Hello World",
  callback = () => {
    console.log(value)
  }
) {
  callback()
}
doSomethingWithValue() // выведет "Hello World"

54. Что такое объекты обертки (Wrapper Objects)?

Примитивные значение, такие как string, number и boolean, исключаяя null и undefined, имеют свойства не смотря на то, что они не являются объектами.

let name = "marko"

console.log(typeof name) // выведет  "string"
console.log(name.toUpperCase()) // выведет  "MARKO"

Значение переменной name является примитивом типа string, которое не имеет ни свойств, ни методов. Однако, в нашем примере, мы применили к этой переменной метод toUpperCase(), что не привело к ошибке, а вывело в консоль MARKO.

Причина этого в том, что это примитивное значение временно конвертировалось или было приведено к типу в объект, и таким образом переменная name ведет себя как объект. Каждый примитивный тип, кроме null и undefined имеет объект обертку. Объектами обертками являются String, Number, Boolean, Symbol и BigInt.

В этом случае вызовa name.toUpperCase(), под капотом выглядит так

console.log(new String(name).toUpperCase()) // выведет  "MARKO"

Вновь созданный объект сразу же выбрасывается после того, как мы закончили работу со свойством или вызовом метода.

55. В чем разница между неявным и явным приведением типов (Implicit and Explicit Coercion)?

Неявное приведение типов - это такое конвертирование значения в иной тип данных, которое осуществляется без участия программиста.

Допустим у нас есть следующий код.

console.log(1 + "6")
console.log(false + true)
console.log(6 * "2")

Первый console.log выведет в консоль 16. В других языках это могло бы привести к ошибке на этапе компиляции, но в JavaScript 1 конвертируется в сроку, при помощи оператора + производится конкатенация строки. JavaScript все сделал за нас, автоматически.

Второй console.log выведет 1. Произойдет конвертация булевых значений в числовые (true - 1, false - 0). Затем произойдет сложение и в результате получаем 1.

Третий console.log выведет 12. Произойдет конвертация '2' в числовое значение, и дальше произойдет операция умножения 6 на 2. Все это произойдет в соответсвии с Правилами приведения типов JavaScript.

Тогда как явное приведение типов происходит при прямом контроле со стороны программиста.

console.log(1 + parseInt("6"))

В этом примере мы используем parseInt для конвертации '6' в число. Затем происходит сложение единицы и шестерки.

56. Что такое NaN и как проверить, что значение равно NaN?

NaN обозначает Not a Number (не число). В JavaScript это такое значение, которое является результатом преоброзования числа в не число.

let a

console.log(parseInt("abc"))
console.log(parseInt(null))
console.log(parseInt(undefined))
console.log(parseInt(++a))
console.log(parseInt({} * 10))
console.log(parseInt("abc" - 2))
console.log(parseInt(0 / 0))
console.log(parseInt("10a" * 10))

JavaScript имеет встроенный метод isNaN, проверяющий значения на то, являются ли они NaN. Но этот метод ведет себя довольно странно.

console.log(isNaN()) // выведет true
console.log(isNaN(undefined)) // выведет true
console.log(isNaN({})) // выведет true
console.log(isNaN(String("a"))) // выведет true
console.log(isNaN(() => {})) // выведет true

Все эти проверки выведут в консоль true, даже если мы явно проверяем не числа.

В ES6 или ECMAScript 2015 рекомендуется использовать метод Number.isNaN, потому что он действительно проверяет число на нечислое значение. Или же можно написать самому вспомогальную функцию, потому что NaN в JavaScript является единстенным значением, которое не равно самому себе.

function checkIfNaN(value) {
  return value !== value
}

57. Как узнать, что значение является массивом?

Мы можем проверить, что значение явялется массивом, с помощью метода Array.isArray, доступного из глобального объекта Array. Он возвращает true, если объект является массивом, или false - если нет.

console.log(Array.isArray(5)) // false
console.log(Array.isArray("")) // false
console.log(Array.isArray()) // false
console.log(Array.isArray(null)) // false
console.log(Array.isArray({ length: 5 })) // false

console.log(Array.isArray([])) // true

Если ваше окружение не позволяет использовать данный метод, то вы можете использовать реализацию полифила.

function isArray(value) {
  return Object.prototype.toString.call(value) === "[object Array]"
}

58. Как узнать, что число четное без использования операторов % или modulo?

Мы можем использовать побитовый оператор И & для решения этой проблемы. Оператор & оперирует своими операндами, обрабатывает их как двоичное значение и выполняет к ним операцию И

function isEven(num) {
  if (num & 1) {
    return false
  } else {
    return true
  }
}

0 явялется двоичным 000.

1 явялется двоичным 001.

2 явялется двоичным 010.

3 явялется двоичным 011.

4 явялется двоичным 100.

5 явялется двоичным 101.

6 явялется двоичным 110.

7 явялется двоичным 111.

и так далее...

a b a & b
0 0 0
0 1 0
1 0 0
1 1 1

Когда мы выводим в консоль выражение 5 & 1, оно выводит 1. Итак, сперва опертор & конвертирует оба числа в бинарное значение, 5 становится 101, а 1 становится 001. Затем сравнивается каждый бит (нули и единицы) с помощью оператора побитового сравнения &. 101 и 001. Как мы видим по таблице ниже, результатом может быть только 1, если и a и b являются единицами.

101 & 001
101
001
001
  • Сперва мы сравниваем самые левые биты 1 & 0. Результатом будет 0.
  • Затем мы сравниваем средние биты 0 & 0. Результатом будет 0.
  • Затем мы сравниваем последние биты 1 & 1. Результатом будет 1.
  • Затем мы ковертируем получившееся бинарное число в десятичное число и получаем 1.

Если мы выведем в консоль выражение 4 & 1, то оно вернет 0. Потому что последний бит от 4 будет 0 и что выражение 0 & 1 возвращает 0.

Если вам сложно понять побитовые операции, то вы можете просто испольовать рекурсию.

function isEven(num) {
  if (num < 0 || num === 1) return false
  if (num == 0) return true
  return isEven(num - 2)
}

59. Как узнать, что в объекте присутствует определенное свойство?

Существует три способа узнать, что свойство присутствует в объекте.

Первый способ - использование оператора in. Синтаксис использования оператора in такой - propertyname in object. Результатом будет true, если свойство существует, или false - если нет.

const o = {
  prop: "bwahahah",
  prop2: "hweasa",
}

console.log("prop" in o) // выведет true
console.log("prop1" in o) // выведет false

Второй способ - использование метода объекта hasOwnProperty. Этот метод доступен для всех объектов javaScript. Он возвращает true, если свойство существует, или false - если нет.

// Тотже объект "o", что и в предыдущем примере
console.log(o.hasOwnProperty("prop2")) // выведет true
console.log(o.hasOwnProperty("prop1")) // выведет false

Третий способ - использование нотации obj["prop"]. Если свойство существует - вернется значение свойства, в обратном случае вернется undefined.

// Тотже объект "o", что и в предыдущем примере
console.log(o["prop"]) // выведет "bwahahah"
console.log(o["prop1"]) // выведет undefined

60. Что такое AJAX?

AJAX расшифровывается как Asynchronous JavaScript and XML (Асинхронный JavaScript и XML). Это группа взаимосвязанных технологий, используемых для асинхронного отображения данных. Это означает, что мы можем посылать запросы на сервер и получать ответы от сервера не перегружая веб страницу.

Технологии, используемые в AJAX:

  • HTML - структура веб страницы
  • CSS - стилизация страницы
  • JavaScript - поведение страницы и обновление DOM
  • XMLHttpRequest API - используется для отправки и получения данных с сервера
  • PHP, Python, Nodejs - некоторые серверные языки

Предыдущая статья Часть 5

Следующая статья Часть 7