10 наиболее распространенных вопросов на собеседовании по JavaScript (часть 2)
JavaScript

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

6. Что такое прототипное наследование (prototypal inheritance)

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

let car = function(model) {
    this.model = model;
};
car.prototype.getModel = function(){
    return this.model;
}
let honda = new car('honda');
console.log(honda.getModel()); //honda
let bmw = new car('bmw');
console.log(bmw.getModel()); //bmw

Функция car называется конструктором. Далее мы добавляем метод getModel в ее прототип, с помощью специальной конструкции car.prototype.getModel(). Если вы не поняли о чем здесь говорится, настоятельно рекомендую ознакомиться с прототипным ООП: https://learn.javascript.ru/prototypes
30% вам зададут этот или похожий вопрос.

7. Разница между объявлением функции (function declaration) и функциональным выражением (function expression)?

function funcA(){
    console.log('function declaration');
};
var funcB = function() {
    console.log('function expression');
}

Как видим, функциональное выражение, — это переменная, которой присваивается функция.
Важная особенность заключается в том, что функция объявленная через function declaration доступна по тексту программы до ее описания. В то время как функциональное выражение ведет себя как переменная, таким образом, к функции можно обратиться только после. Если мы в предыдущем примере, в самом начале допишем две строки:

console.log(funcA()); //function declaration
concole.log(funcB()); //Uncaught ReferenceError: funcB is not defined.

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

8. Что такое промисы (promises) и для чего их используют.

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

$.ajax({
    url: "test.json",
    success: function(r) {
        $.ajax({
            url: "baz.json?" + r.test,
            success: function(result) {
                $("#div1").html(result);
            }
        });
    }
});

Видите, насколько сильно ветвится данный код? Теперь, напишем тоже самое с использованием промисов (схематично):

var p1 = new Promise(function(resolve, reject) {
    resolve($.ajax('test.json'));
});

p1.then(function(r){
    return new Promise(…);
}).then(function(result){
    $(“#div1”).html(result);
});

9. Вопрос про setTimeout()

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

console.log('a');
console.log('b');
console.log('c');
//увидим последовательный вывод a затем b и с.
</pre>

Теперь сделаем тоже самое, только вывод 'а' обернем в setTimeout().
<pre lang="js">
setTimeout(function() {
    console.log('a'); 
}, 0);

По логике вещей, поскольку таймаут равен 0, мы можем предположить, что последовательность вывода останется такой же. Однако на самом деле, мы увидим сначала b, потом c и только в конце – a.
Так происходит потому, что когда мы использует setTimeout, код, который в него заключен, становится асинхронным. JS выполнит его после того, как освободится стэк. То есть после b и c.

10. Замыкания (closure) и как их использовать

Наверняка вам зададут вопрос на собеседовании.

Когда одна функция возвращает другую функцию (или объект), последняя содержит окружение своего как бы «родителя». Обратимся к примеру:

let bar = function() {
    let i = 0;
    return {
        setI(b) {
            i = b;
        },
        getI() {
            return i;
        }
    }
};

let x = bar();
x.setI(2);
console.log(x.getI()); //2

Напоследок, хотелось бы посоветовать не спешить с ответами при прохождении собеседования, особенно на вопросы, связанные с анализом предложенного кода. Часто очевидные на первый взгляд вопросы содержат хитрости и ловушки. Остановитесь, подумайте лишнюю минутку. Задайте уточняющие вопросы — это продемонстрирует вашу внимательность и ответственное отношение к делу. Поможет выявить интервьюверу ход ваших мыслей. Собственно, в основном для этого и задаются хитрые или сложные задачи. Гораздо важнее продемонстрировать правильное мышление, даже если ответ на вопрос в итоге будет неверным.

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

  • Boris:

    Спасибо за статью! Сейчас готовлюсь к собеседованию, читаю такого рода материалы.
    У вас опечатка:
    setI(b) {
    i = k;
    },
    Наверное:
    setI(b) {
    i = b;
    },

Добавить комментарий