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

Первоначально появилось на: https://www.zeolearn.com/magazine/cracking-the-front-end-developer-interview

В. Что вы знаете о вызове, привязке и применении? В чем разница между вызовом и привязкой?

A. Мы читали об this в предыдущей части. Его значение определяется тем, как функция вызывается. Это была неявная привязка. Но мы также можем вызвать нашу функцию с помощью нашего собственного this, используя call или apply. Это называется явной привязкой.

var myMethod = function () {
    console.log(this);
};
var myObject = { myMethod: myMethod };
var newObject = { myNewMethod: myMethod};
myMethod() // this === window
myObject.myMethod() // this === myObject
myMethod.call(newObject, args1, args2, …) // this === newObject
myMethod.apply(newObject, [array of args]) // this === newObject

Хороший пример этого можно найти по адресу https://codepen.io/shoaibkhan94/pen/qxaEPw?editors=1010.

Итак, что делает метод call? Он вызывает функцию с заданным значением this и аргументами, предоставленными индивидуально. Что делает метод apply? Он аналогичен вызову с принципиальной разницей в том, что call () принимает список аргументов, а apply () принимает единственный массив. аргументов.

А как насчет метода bind? Метод bind () создает новую функцию, при вызове которой для ключевого слова this устанавливается указанное значение.

myNewMethod = myMethod.bind(myObject);
myNewMethod(); // this === myObject

Это может показаться похожим на метод call (). Основные различия между bind () и call () заключаются в следующем:

call () сразу выполняет функцию, к которой он был вызван. bind () возвращает новую функцию вместе с this, установленным на this, указанное внутри bind (). .

В. Что такое закрытие и как / зачем вам его использовать?

A. В официальной документации MDN говорится: замыкание - это комбинация функции и лексической среды, в которой эта функция была объявлена. Чтобы понять замыкание, вы должны понимать область действия и цепочка областей действия (область действия я рассмотрел в предыдущей статье). Рассмотрим этот пример:

// We have two functions. One is named outer & other is named inner.
//this is inner’s global scope
function outer(name) {
    //this is inner’s outer scope
    var text = ‘Hello ‘ + name;
    var inner = function() {
        //this is inner’s local scope
        console.log(text);
    }
    inner();
}
outer(‘John’); //Outputs ‘Hello John’.

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

Каждый раз, когда мы создаем функцию внутри другой функции, мы создаем замыкание. Другой пример :

function init(args){
    var firstName = args.firstName;
    var lastName = args.lastName;
    function returningFunc(action){
        return firstName + “ “ + lastName + “ “ + “is ” + action;
    }
    return returningFunc;
}
var data = {firstName: “Alan”, lastName: “Smith” };
var zombieOne = init(data); //when we initialize the outer function, it returns undefined. The outer function is dead, but…
/*
20 lines of code later…
*/
zombieOne(“walking”); // Outputs ‘Alan Smith is walking’

Причина, по которой мы все еще можем получить доступ к имени этого «зомби», не связана с какой-либо научной фантастикой, а потому, что замыкания не сохраняют ценность. Значения статичны. Вместо этого они хранят ссылки на значения в своих цепочках областей видимости. Удивительно то, что если вы измените значение переменной в цепочке областей видимости перед возвратом замыкания, то будет обновлено то же значение, что и в замыкании. Пример:

function outer() {
    // Local variable that ends up within closure
    var num = 30;
    var say = function() { console.log(num); }
    num++;
    return say;
}
var sayNumber = outer();
sayNumber(); // logs 31

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

Использование закрытия:

Создание модульных шаблонов с частными переменными и функциями. Пример:

var zombieOne = (function(){
    //private variables
    var firstName = “”;
    var lastName = “”;
    //private functions
    function init(data){
        firstName = data.firstName;
        lastName = data.lastName;
    }
    function combineName(){
        return firstName + “ “ + lastName;
    }
    function gerunding(action){
        return firstName + “ “ + lastName + “ “ + “is ” + action;
    }
    //public functions
    return {
        getName: function(){
            return combineName();
        },
        setName: function(data){
            return init(data);
        },
        setAction: function(action){
            return gerunding(action);
        }
    };
})();
var data = {firstName: “Alan”, lastName: “Smith” };
zombieOne.setName(data);
zombieOne.getName(); // “Alan Smith”
zombieOne.setAction(“walking”);// “Alan Smith is walking”

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

P.S. : В последнем примере мы создали анонимное закрытие или выражение немедленного вызова функции (IIFE). Они выполняются немедленно и позволяют нам управлять конфиденциальностью.

В. Что такое обещания? Каковы плюсы и минусы использования обещаний вместо обратных вызовов?

A. Обещание - это объект, который представляет значение, доступное в результате асинхронной операции: либо разрешенное значение, либо причину, по которой оно не разрешено (например, произошла сетевая ошибка).

Согласно MDN Promise находится в одном из следующих состояний:

  • ожидает: начальное состояние, ни выполнено, ни отклонено.
  • выполнено: означает, что операция успешно завершена.
  • отклонено: это означает, что операция не удалась.

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

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

function getUserSuccess(user) {
    console.log(“The User is: “ + user);
}
function getUserFailure(error) {
    console.log(“Failed to get user: “ + error);
}
API.getUser(getUserSuccess, getUserFailure);

… С введением обещаний функции теперь возвращают обещание, к которому вы можете вместо этого прикрепить свои обратные вызовы:

let promise = API.getUser();
promise.then(getUserSuccess, getUserFailure);

или просто

API.getUser().then(getUserSuccess, getUserFailure);

Плюсы и минусы

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

API.getUser(function(user) {
    API.getUserAddress(user, function(address) {
        // do something with address
        API.saveUserAddress(address, function(newAddress) {
            console.log(‘New User Address: ‘ + newAddress);
        }, failureCallback);
    }, failureCallback);
}, failureCallback);

WithWith promises, мы можем прикрепить наши обратные вызовы к обещаниям, возвращаемым функциями, и сформировать цепочку обещаний:

API.getUser().then(function(user) {
    return API.getUserAddress(user);
})
.then(function(address) {
    // do something with address
    return API.saveUserAddress(address);
})
.then(function(newAddress) {
    console.log(‘New User Address: ‘ + newAddress);
})
.catch(failureCallback); //One catch to handle all failures

Обещания также упрощают обработку ошибок. Учти это:

save().then(handleSuccess,handleError);

С помощью обещаний вы не должны обрабатывать ошибки внутри .then (). Кроме того, handleSuccess () может сам выдать ошибку. Поэтому это считается антипаттерном. Рекомендуется следующее:

save().then(handleSuccess).catch(handleError);

В приведенном выше примере .catch () будет обрабатывать отклонения либо от save (), либо от ошибок от handleSuccess (). Поэтому рекомендуется заканчивать все цепочки обещаний с помощью .catch ().

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

В. В чем разница между наследованием классов и прототипов?

A. Наследование в JavaScript отличается от большинства других языков. Система объектов в JavaScript основана на прототипах, а не на классах.

Объекты в JavaScript - это просто набор пар имени (ключа) и значения.

Согласно MDN, когда дело доходит до наследования, в JavaScript есть только одна конструкция: объекты. Каждый объект имеет частное свойство, которое содержит ссылку на другой объект, называемый его прототипом. У этого объекта-прототипа есть собственный прототип, и так до тех пор, пока не будет достигнут объект с нулевым значением в качестве его прототипа. По определению, null не имеет прототипа и действует как последнее звено в этой цепочке прототипов.

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

function Greeter (name) {
    this.name = name || ‘John Doe’;
}
Greeter.prototype.hello = function hello () {
    return ‘Hello, my name is ‘ + this.name;
}
var george = new Greeter(‘George’);
var msg = george.hello();
console.log(msg); // Hello, my name is George

Цепочка прототипов

Каждый раз, когда вы пытаетесь получить доступ к свойству объекта, сначала проверяются собственные свойства объекта. Если он не найден, то проверяется [[Prototype]], и поэтому проверка идет вверх по цепочке прототипов, пока не вернется к Object.prototype, который является корневым делегатом для большинства объектов.

Вот пример на Codepen, чтобы объяснить это дальше.

Итак, это была краткая информация о наследовании прототипов в JS, а теперь давайте вернемся к исходному вопросу о наследовании классов и прототипов.

Вот пример на Codepen, чтобы объяснить разницу между ними.

В приведенном выше примере следует отметить следующие моменты:

  1. Когда мы вызываем «new Point (3, 4)», по сути, мы создаем новый объект, который наследуется от Point.prototype, тогда конструктор Point () вызывается в контексте нового объекта. Так создаются и инициализируются свойства нового объекта.
  2. Когда мы вызываем «new Point3D (3, 4, 5)» для создания нового объекта, мы снова создаем новый объект, который наследуется от Point3D.prototype, который наследуется от объекта Point и вызывает конструктор Point3D () в контексте новый объект.
  3. Вот чем отличается прототипное наследование: мы напрямую создаем новый объект из существующего объекта, без понятия классов. Мы используем «Object.create» для создания нового объекта. Он принимает объект в качестве параметра, который будет прототипом для нового объекта.
  4. Обратите внимание, что «p2» и «point_3d» создаются одинаково. Однако мы расширяем point_3d дополнительными свойствами и методами.
  5. Важно отметить, что в JavaScript нет понятия наследования на основе классов. Мы просто псевдо-реализуем его, используя свойство «prototype» для построения цепочки наследования.

Наследование классов. Экземпляры наследуются от классов, которые являются планом (описанием) объекта. Экземпляры создаются с помощью функций-конструкторов с ключевым словом new.

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

TL;DR:

  • класс - это план.
  • прототип - это экземпляр объекта.

В следующей статье я расскажу о вопросах HTML, CSS и Интернета.