1. В чем смысл оборачивания всего содержимого JavaScript-файла в функцию?

    Этот шаблон называется IIFE - Immediately Invoked Function Expression (немедленно вызываемое функциональное выражение). Этот подход позволяет:

    • обеспечить коду собственный блок видимости, то-есть контекст выполнения

    • избежать загрязнения глобальной области видимости глобальными переменными

    • избежать неумышленного переопределения уже существующих переменных в глобальной области видимости

  2. В чем смысл и польза указания use strict в начале JavaScript-файла?

    Команда use strict включает так называемый строгий режим. В этом режиме предупреждения становятся ошибками, что помогает в написании более чистого и безопасного кода, менее уязвимого к ошибкам в продакшене.

  3. Что такое NaN? Какого типа это значение? Как можно узнать, равно ли значение переменной NaN?

    NaN расшифровывается как "Not A Number", это "falsey" (ложное) значение.

    Выражение typeof NaN возвращает тип Number.

    Проверить значение переменной на соответствие NaN можно, воспользовавшись встроенным методом isNaN() или используя оператор тройного равенства ===.

  4. Что такое замыкание в JavaScript? Приведите пример.

    Замыкание в JavaScript - это комбинация функции и лексического окружения, в котором она была определена. Это позволяет ей обращаться к переменным и функциям этого лексического окружения в дальнейшем.

    В следующем примере мы определяем функцию makeCounter(), которая фактически является фабричной функцией. При вызове она возвращает дочернюю функцию, которая имеет доступ к лексическому окружению внешней функции, то-есть функции makeCounter(). Таким образом, возвращаемая функция запоминает переменную counter и в последующем изменяет ее значение.

    function makeCounter(initial = 0) {
      let counter = initial;
    
      return function() {
        return counter += 1;
      }
    }
    
    const counterA = makeCounter(0);
    
    console.log(counterA()); // 1
    console.log(counterA()); // 2
    
    const counterB = makeCounter(100);
    
    console.log(counterB()); // 101
    console.log(counterB()); // 102
  5. Как можно клонировать объект?

    Можно использовать оператор остатка ....

    Можно использовать Object.assign(newObj, oldObj).

    Но эти подходы не позволяют выполнить глубокое клонирование. Поэтому, если нам нужно клонировать объект со вложенными объектами, мы можем использовать либо метод какой-либо библиотеки (привет, lodash), либо сделать это средствами встроенного объекта JSON.

    JSON.parse(JSON.stringify(objectToClone))
  6. Как можно добавить элемент в начало и в конец массива?

    Чтобы добавить элемент в начало массива, можно использовать Array.prototype.unshift(). Для добавления элемента в конец массива подойдет Array.prototype.push().

  7. В чем разница между undefined и is not defined?

    undefined - это значение, присваемое объявленной, но не проинициализированной переменной.

    Мы получаем undefined, обращаясь к существующей переменной. А в случае обращения к несуществующей (необъявленной) переменной, мы получим ошибку is not defined.

  8. Как проверить, является ли объект массивом?

    Для этого можно использовать встроенный метод Array.isArray().

  9. Что такое hoisting (поднятие) в JavaScript?

    Поднятие - это поведение компилятора JavaScript, заключающееся в поднятии объявлений переменных и функций в начало области видимости.

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

    По этой причине, например, мы можем использовать до объявления функцию, объявленную через Function Declaration, но не можем ту, которая объявлена через Function Expression.

  10. Что такое this?

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

  11. Как работает прототипное наследование?

    Если отвечать кратко, в JavaScript все является объектами. Эти объекты связаны цепочками прототипов, по которым им передаются методы и свойства. При обращении к свойству или методу объекта сначала происходит поиск этого свойства у самого объекта. В случае неудачи поиск перенаправляется в его прототип, затем в прототип прототипа и так далее, пока искомое свойство не будет найдено, либо пока не закончится цепочка прототипов.

  12. Объясните, почему запись function foo(){}() вызывает ошибку и не работает, как IIFE?

    Здесь дело в том, что круглые скобки вызова функции добавлены сразу после Function Declaration. Однако, они могут следовать только за выражением (expression). Поэтому мы должны либо прибегнуть к варианту с Function Expression, либо обернуть Function Declaration в скобки, тем самым превратив его в выражение.

    const foo = function(){}()
    
    // либо
    
    (function foo(){})()
    
    // либо со стрелочной функцией
    
    (() => {})()
  13. В чем разница между null, undefined и undeclared?

    null - это в прямом смысле "ничего". Можно использовать это значение в качестве плейсхолдера.

    undefined - это значение для случая "объявлено, но не инициализировано".

    undeclared - это ошибка, возникающая в случае обращении к необъявленной переменной.

  14. В чем разница между Array.prototype.forEach и Array.prototype.map?

    Array.prototype.forEach - это инструмент обхода цикла процедурно, а Array.prototype.map - функционально.

    .forEach просто проходится по массиву с выполнением переданного обратного вызова на каждой итерации, а .map создает и возвращает новый массив на основе исходного, выкладывая по кирпичику на каждой итерации.

  15. В каких случаях используются анонимные функции?

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

  16. Объясните разницу между const person = Person() и const person = new Person() при function Person(){}

    Если функция Person() не возвращает явным образом создаваемый экземпляр, то вариант const person = Person() присвоит константе person значение undefined, поскольку именно таков результат void функции.

    Если функция Person явным образом возвращает экземпляр, он станет значением константы person при const person = Person().

    Однако, вариант с использование оператора new "выигрывает", поскольку он устанавливает корректную связь объекта person с цепочкой прототипов Person, в то время как выражение const person = Person() просто присваивает константе результат вызова функции.

  17. В чем разница между Function.prototype.call и Function.prototype.apply?

    Оба метода вызывают исходный метод с подмененным контекстом, но .call принимает параметры через запятую, а .apply - массивом.

  18. Как работает Function.prototype.bind?

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

  19. Что вы знаете об AJAX?

    AJAX = Asynchronous Javascript And XML. Это подход к асинхронному (неблокирующему) обмену данными с сервером.

    Изначально для решения подобной задачи использовался объект XMLHttpRequest , сейчас же более актуален дружелюбный к обещаниям (Promise) fetch API.

  20. В чем разница между атрибутами и свойствами?

    Атрибут - это HTML-термин, в то время как свойство - термин из JavaScript. Иными словами, если речь идет о значении в HTML-разметке, мы говорим об атрибуте. Однако, если имеется в виду свойство объекта, к которому мы получили доступ средствами JavaScript - вернее называть это свойством.

  21. В чем разница между == и ===?

    Оператор двойного равенства производит приведение типов, оператор строгого равенства - нет.

  22. Почему лучше оставлять глобальную область видимости "как есть" и не трогать ее?

    По той причине, что свойства глобальной области видимости может изменить любой JavaScript-код, имеющий к ней доступ. Также, это грозит конфликтами имен.

  23. Что такое SPA и как сделать его SEO-friendly?

    Single Page Application - это реализация веб-приложения таким образом, чтобы при первой загрузке пользователь получал все ресурсы, необходимые для того, чтобы избавиться от загрузки страницы с нуля при совершении интерактивных действий с интерфейсом.

    Основную роль в SPA играет JavaScript, реализующий механизмы динамического обновления данных без перезагрузки страницы.

    Для того, чтобы сделать SPA SEO-friendly, можно обратиться к таким решениям, как предварительный рендеринг или серверный рендеринг.

  24. Какие преимущества и недостатки у использования Promise API вместо обратных вызовов?

    Обещания избавляют разработчиков от ада обратных вызовов, но это не единственное их достоинство.

    Важно также отметить, что пользуясь обратными вызовами, мы зачастую были вынуждены "верить" стороннему коду. А вызовет ли он наш коллбэк? А вызовет ли он его корректное количество раз? А не вызовет ли он его слишком рано или слишком поздно?

    Представьте, что функция, снимающая деньги со счета пользователя, передается коллбэком в сторонний (в той или иной степени) код. Что будет, если он вследствие внесенных со стороны изменений начнет вести себя некорректно и, скажем, начнет вызывать эту функцию пять раз вместо одного?

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

  25. Какие инструменты вы используете при отладке?

    При первой встрече с проблемой я, не спеша усложнять себе жизнь, обращаюсь к console.log. Если это не помогает, вызываю тяжелую артиллерию в виде браузерного отладчика.

  26. Какие конструкции языка вы используете для обхода массивов и объектов?

    В случае с массивами, это чаще всего forEach и map. Реже возникает необходимость в for, for in, for of, reduce, filter и подобных.

    А чтобы обойти объект, понадобится немного изобретательности. Один из вариантов - получить ключи с помощью Object.keys, по которым впоследствии пройти с помощью forEach. Либо же можно воспользоваться Object.values, Object.entries, Object.keys.

  27. Объясните разницу между изменяемыми и неизменяемыми значениями

    Значения примитивных типов (например, строка или число) не могут быть изменены после того, как попали в память.

    Значения объектных типов (объекты, массивы) могут изменяться в ходе работы программы.

  28. Объясните разницу между синхронными и асинхронными функциями

    JavaScript - это однопоточный язык, то-есть функции выполняются в синхронном порядке. Приложение блокируется на время выполнения каждой конкретной функции. Так происходит по той причине, что JavaScript имеет только один стек вызовов.

    С другой стороны, есть асинхронный способ выполнения функций, когда мы не блокируем весь интерфейс благодаря тому, что не дожидаемся выполнения функции, а подписываемся на событие с передачей обратного вызова. Ну, или мы можем иметь дело с обещанием или с прочими внешними API вроде setTimeout.

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

  29. Что такое цикл событий? В чем разница между стеком вызовов и очередью задач?

    Стек вызовов - это структура данных (первым вошел, последним вышел), используемая для отслеживания порядка выполнения функций в текущем контексте (области видимости).

    Очередь задач - это структура данных (первым вошел, первым вышел), используемая для отслеживания выполнения асинхронных функций, готовых оказаться в стеке вызовов.

    Цикл событий - это механизм, на каждом тике выполняющий функции из стека вызовов и, если он оказывается пустым, перемещающий задачи из очереди задач в стек вызовов для выполнения.

  30. В чем разница между let, const и var?

    var

    • поднимается в начало области видимости функции при компиляции

    • объявляет переменную, которая может быть перезаписана

    • объявляет переменную, которая может быть переопределена

    let

    • поднимается в начало области видимости блока при компиляции

    • объявляет переменную, которая может быть перезаписана

    • объявляет переменную, которая не может быть переопределена

    const

    • поднимается в начало области видимости блока при компиляции

    • объявляет переменную, которая не может быть перезаписана или переопределена

  31. В чем разница между ES6 class и ES5 function constructor?

    Классы, добавленные в стандарте EcmaScript 6, всего лишь синтаксический сахар поверх всем известных прототипов.

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

  32. Что такое функция высшего порядка?

    Функция, принимающая функцию обратного вызова в качестве аргумента.

  33. Что такое DOM?

    DOM - Document Object Model (объектная модель документа). Другими словами, это дерево всех узлов страницы, которые распознал браузер в процессе обработки HTML-разметки.

    DOM - это интерфейс, позволяющий JavaScript-коду взаимодействовать с шаблоном.

  34. В чем разница между областью видимости функции и блочной областью видимости?

    И то, и то является полноценной областью видимости. Различие наблюдается при использовании ключевого слова var, которое ограничивается только областью видимости функции, но не блочной областью видимости.

  35. Что произойдет в результате выражения var foo = 10 + "20" и почему?

    Переменная foo примет значение "1020".

    В JavaScript это поведение называется приведением типов. Если хотя бы один из операндов является строкой, второй также будет преобразован в строку.

Комментарии (13)


  1. dopusteam
    16.09.2021 23:31
    +5

    Проверить значение переменной на соответствие NaN можно, воспользовавшись встроенным методом isNaN() или используя оператор тройного равенства ===

    Оператор строгого равенства (а не тройного), не сработает. NaN === NaN вернёт false.

    Можно использовать оператор остатка ....

    Это не оператор остатка

    В чем разница между undefined и is not defined

    В чем разница между nullundefined и undeclared

    Серьёзный вопрос

    Для этого можно использовать встроенный метод isArray()

    Встроенный метод чего? Как его вызвать?

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

    Покажите пример использование переменной до её объявления

    Array.prototype.forEach - это инструмент обхода цикла процедурно, а Array.prototype.map - функционально.

    Можно подробнее?


    1. WalkInWay
      17.09.2021 09:02
      +2

      Не смотря на то, что многие вопросы в стать е действительно спорные. Но я могу ответить на часть поставленных вами.

      Оператор строгого равенства (а не тройного), не сработает. NaN === NaN вернёт false.

      Благодаря этому мы и определим :)

      function myIsNaN(value) {
          // Тут используем строгое равенство :) 
          return (value === value) === false;
      }

      Покажите пример использование переменной до её объявления

      Так можно делать с var (но не нужно!) и с функциями.

      myFunc();
      
      function myFunc() {
          x = 5
          console.log(x);
          var x = 2
      }


  1. dopusteam
    16.09.2021 23:45

    В оригинале

    The main difference is that map returns a new array while forEach doesn’t.

    Also, map doesn’t mutate the original array instead makes a new modified/updated copy.

    I would always pick map because it does allow method chaining

    Перевод

    Array.prototype.forEach - это инструмент обхода цикла процедурно, а Array.prototype.map - функционально.

    .forEach просто проходится по массиву с выполнением переданного обратного вызова на каждой итерации, а .map создает и возвращает новый массив на основе исходного, выкладывая по кирпичику на каждой итерации.

    ¯\_(ツ)_/¯ 


    1. Sadler
      18.09.2021 18:38

      map doesn’t mutate the original array

      В общем случае это неверно, так что даже хорошо, что этого нет в переводе. map имеет доступ к элементам оригинального массива и может спокойно их мутировать. Это антипаттерн, но язык формально позволяет.


  1. Metotron0
    17.09.2021 01:06

    У меня нет опыта прохождения собеседований, поэтому спрошу: это вопросы, которые задаются условному react-разрботчику между вопросами про фреймворк/библиотеку, чтобы понять, что человек знает не только react, но и сам язык? Или где-то есть собеседования, где ищут разработчиков на голом JS и спрашивают только вот такое? Мне кажется, это довольно простые вопросы, и если верно второе предположение, то это странная разработка, в которой задачи достаточно простые (не разработка своего убийцы ангуляра), но не захотели брать фреймворк, а зачем-то решили писать без всего, что, скорее всего, приведёт к созданию собственного подобия фреймворка или библиотеки.


    1. Cobalt
      17.09.2021 10:40
      +1

      Скорее всего эти вопросы для отсеивания тех условных react-разработчиков, которые начали свой путь в разработке сразу с условного react и умеют только "формочки верстать"


    1. Mu57Di3
      17.09.2021 12:45

      Я спрашиваю пдобные вопросы на собеседовании. Процентов 70 не могут вообще или затрудняются на них ответить. Если не отвечают на эти к вопросам по React я даже не перехожу.


  1. enkryptor
    18.09.2021 13:51
    +1

    Вот мой .push() в список фактических ошибок в вопросах. Точнее, в данном случае ошибка в ответе:

    В JavaScript это поведение называется приведением типов. Если хотя бы один из операндов является строкой, второй также будет преобразован в строку.

    Совсем наоборот, операнды арифметических выражений в JS как раз приводятся к числу. Можете проверить сами:

    "3" - 2 // 1
    3 * "2" // 6
    "2" ** "3" // 8

    Исключением является оператор +. Он используется как для сложения, так и для конкатенации строк. Если хотя бы один операнд не является числом, операция интерпретируется как конкатенация и оба значения приводятся к строке:

    1 + {} // "1[object Object]"

    Как видите, при этом совсем не обязательно, чтобы "один из операндов являлся строкой".

    В целом вопросы неплохие, на собеседованиях вполне можно несколько таких задать. Некоторые правда очень зависят от контекста, например тот же "В чем разница между атрибутами и свойствами". Но может это и к лучшему и исправлять ничего не надо — хороший разработчик обязательно уточнит, а плохой начнёт угадывать.


    1. SeokkySss Автор
      06.10.2021 11:44

      Если хотя бы один операнд не является числом, операция интерпретируется как конкатенация и оба значения приводятся к строке

      Тут ни один операнд не является числом, но операция не интерпретируется как конкатенация, значения не приводятся к строке

      console.log(true + false) // 1


  1. OlegPatron92
    18.09.2021 13:53
    +1

    В чем разница между ES6 class и ES5 function constructor?

    Классы, добавленные в стандарте EcmaScript 6, всего лишь синтаксический сахар поверх всем известных прототипов.

    На Хабре вроде была статья, что ES6 не просто синтаксический сахар ^_^

    PS Мне скоро 30 и совсем недавно я начал замечать, что собеседующие 25 и младше задают именно такие вопросы, а 35 и выше, совсем другие. Например, в двух словах рассказать, как построить архитектуру приложения для решения заданой задачи.


    1. savostin
      20.09.2021 12:04
      +1

      Просто мало джунов после 35


      1. Metotron0
        21.09.2021 00:21

        Но тут речь про собеседующих, а не тех, кто устраивается джуном.


  1. demimurych
    18.10.2021 22:45
    -1

    Что такое SPA и как сделать его SEO-friendly?

    И когда это вдруг SPA перестало быть SEO-friendly? Наверное тогда, когда кто-то решил что SPA это обязательно client-side rendering.

    Удивительно что люди не знают о том, что первые SPA делались даже в ИЕ6, то есть где то в 2002 году. А полностью полноценными они стали с появлением возможности изменять state в History APi. Кажется в 2010 году. 

     

    Объясните разницу между изменяемыми и неизменяемыми значениями

    Значения примитивных типов (например, строка или число) не могут быть изменены после того, как попали в память.

    В JavaScript нет примитивных типов и никогда не было. Глава 6 ECMA Spec.

     Всегда было любопытно, откуда возник этот странный миф о примитивных и ссылочных типах, и почему он до сих пор занимает чуть ли не первое место в умах JS разработчиков. 

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

     

    Значения объектных типов (объекты, массивы) могут изменяться в ходе работы программы.

    Все типы в JS работают абсолютно одинаково. Никакой разницы в том, каким образом происходит работа с данными в обьекте или в строке - нет. И там и там данные имутабельны. 

     

    В чем разница между let, const и var?

    var объявляет переменную, которая может быть переопределена

    Под словом переопределенная видимо подразумевается то, что можно опять писать var. 

    Любопытно то, что на уровне bytecode ignition, конструкции типа

    var a='str1';
    var a='str2';
    let b='str3'
    b ='str4'

    приведут к генерации абсолютно идентичного кода.

      221 S> 0x27c9c7b0c952 @   12 : 12 02             LdaConstant [2]
             0x27c9c7b0c954 @   14 : 26 f9             Star r2
      237 S> 0x27c9c7b0c956 @   16 : 12 03             LdaConstant [3]
             0x27c9c7b0c958 @   18 : 26 f9             Star r2
      253 S> 0x27c9c7b0c95a @   20 : 12 04             LdaConstant [4]
             0x27c9c7b0c95c @   22 : 26 f8             Star r3
      260 S> 0x27c9c7b0c95e @   24 : 12 05             LdaConstant [5]
             0x27c9c7b0c960 @   26 : 26 f8             Star r3

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

    Так же любопытно, почему о бесполезном переопределении так много написано, а о том, что обязан знать каждый JS разработчик использующий let или const - то есть о TDZ ни слова.