— подписывайтесь на меня на github

Вопросы

1. В чем разница между undefined и null?

Прежде чем понять разницу между undefined и null, мы должны понять сходство между ними.

  • Они относятся к 7 примитивным типам JavaScript.
let primitiveTypes = ['string','number','null','undefined','boolean','symbol', 'bigint'];
  • Это ложные значения. Значения, которые оцениваются как ложные при преобразовании в логическое значение с использованием Boolean(value) или !!value.
console.log(!!null); //logs false
   console.log(!!undefined); //logs false
   console.log(Boolean(null)); //logs false
   console.log(Boolean(undefined)); //logs false

Хорошо, давайте поговорим об отличиях.

  • undefined — это значение по умолчанию для переменной, которой не присвоено конкретное значение. Или функция, которая не имеет явного возвращаемого значения, например. console.log(1). Или свойство, которого нет в объекте. Механизм JavaScript делает это за нас, назначая значение undefined.
let _thisIsUndefined;
  const doNothing = () => {};
  const someObj = {
    a : "ay",
    b : "bee",
    c : "si"
  };
  console.log(_thisIsUndefined); //logs undefined
  console.log(doNothing()); //logs undefined
  console.log(someObj["d"]); //logs undefined
  • null — это 'значение, которое не представляет никакого значения'. null – это значение, которое было явно определено для переменной. В этом примере мы получаем значение null, когда метод fs.readFile не выдает ошибку.
fs.readFile('path/to/file', (e,data) => {
     console.log(e); //it logs null when no error occurred
     if(e){
       console.log(e);
     }
     console.log(data);
   });

При сравнении null и undefined мы получаем true при использовании == и false при использовании ===. О причине можно прочитать здесь.

console.log(null == undefined); // logs true
   console.log(null === undefined); // logs false

2. Что делает оператор &&?

Оператор && или Логическое И находит первое ложное выражение в своих операндах и возвращает его, а если не находит ни одного ложного выражения он возвращает последнее выражение. Он использует короткое замыкание, чтобы предотвратить ненужную работу. Я использовал это в блоке catch при закрытии соединения с базой данных в одном из моих проектов.

console.log(false && 1 && []); //logs false
   console.log(" " && true && 5); //logs 5

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

const router: Router = Router();
  router.get('/endpoint', (req: Request, res: Response) => {
     let conMobile: PoolConnection;
     try {
        //do some db operations
     } catch (e) {
     if (conMobile) {
      conMobile.release();
     }
  }
});

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

const router: Router = Router();
router.get('/endpoint', (req: Request, res: Response) => {
  let conMobile: PoolConnection;
  try {
     //do some db operations
  } catch (e) {
    conMobile && conMobile.release()
  }
});

3. Что делает оператор ||?

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

console.log(null || 1 || undefined); //logs 1
function logName(name) {
  var n = name || "Mark";
  console.log(n);
}
logName(); //logs "Mark"

4. Является ли использование оператора + или унарного плюса самым быстрым способом преобразования строки в число?

Согласно Документации MDN + — это самый быстрый способ преобразования строки в число, поскольку он не выполняет никаких операций над значением, если оно уже является числом.

5. Что такое ДОМ?

DOM означает Объектная модель документа — это интерфейс (API) для документов HTML и XML. Когда браузер впервые читает (разбирает) наш HTML-документ, он создает большой объект, действительно большой объект на основе HTML-документа, это DOM. Это древовидная структура, созданная на основе HTML-документа. DOM используется для взаимодействия и изменения структуры DOM или отдельных элементов или узлов.

Представьте, что у нас есть такая структура HTML.

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <meta http-equiv="X-UA-Compatible" content="ie=edge">
   <title>Document Object Model</title>
</head>
<body>
   <div>
      <p>
         <span></span>
      </p>
      <label></label>
      <input>
   </div>
</body>
</html>

Эквивалент DOM будет таким.

Объект document в JavaScript представляет DOM. Он предоставляет нам множество методов, которые мы можем использовать для выбора элементов, обновления содержимого элементов и многого другого.

6. Что такое распространение событий?

Когда событие происходит с элементом DOM, это событие не происходит полностью с одним этим элементом. На фазе всплытия событие всплывает или переходит к своему родителю, к бабушке и дедушке, к родителю бабушки и дедушки, пока не достигнет window, находясь в Фаза захвата событие начинается с window до элемента, вызвавшего событие, или event.target.

Распространение событий состоит из трех этапов.

  1. Фаза захвата — событие начинается с window, затем переходит к каждому элементу, пока не достигнет целевого элемента.
  2. Целевая фаза — событие достигло целевого элемента.
  3. Фаза всплытия — событие всплывает вверх от целевого элемента, затем поднимается вверх по каждому элементу, пока не достигнет window.

7. Что такое пузыри событий?

Когда событие происходит с элементом DOM, это событие не происходит полностью с одним этим элементом. На этапе всплытия событие всплывает или переходит к своему родителю, к бабушке и дедушке, к родителю бабушки и дедушки, пока не достигнет window.

Если у нас есть пример такой разметки.

<div class="grandparent">
    <div class="parent">
      <div class="child">1</div>
    </div>
  </div>

И наш js-код.

function addEvent(el, event, callback, isCapture = false) {
  if (!el || !event || !callback || typeof callback !== 'function') return;
  if (typeof el === 'string') {
    el = document.querySelector(el);
  };
  el.addEventListener(event, callback, isCapture);
}
addEvent(document, 'DOMContentLoaded', () => {
  const child = document.querySelector('.child');
  const parent = document.querySelector('.parent');
  const grandparent = document.querySelector('.grandparent');
  addEvent(child, 'click', function (e) {
    console.log('child');
  });
  addEvent(parent, 'click', function (e) {
    console.log('parent');
  });
  addEvent(grandparent, 'click', function (e) {
    console.log('grandparent');
  });
  addEvent(document, 'click', function (e) {
    console.log('document');
  });
  addEvent('html', 'click', function (e) {
    console.log('html');
  })
  addEvent(window, 'click', function (e) {
    console.log('window');
  })
});

Метод addEventListener имеет третий необязательный параметр useCapture со значением по умолчанию false, событие произойдет на фазе всплытия, если true событие произойдет на этапе захвата . Если мы нажмем на элемент child, он зарегистрирует child, parent, grandparent, html, document и window соответственно на консоли. Это Всплывающие события.

8. Что такое захват событий?

Когда событие происходит с элементом DOM, это событие не происходит полностью с одним этим элементом. На этапе захвата событие начинается с window вплоть до элемента, вызвавшего событие.

Если у нас есть пример такой разметки.

<div class="grandparent">
    <div class="parent">
      <div class="child">1</div>
    </div>
  </div>

И наш js-код.

function addEvent(el, event, callback, isCapture = false) {
  if (!el || !event || !callback || typeof callback !== 'function') return;
  if (typeof el === 'string') {
    el = document.querySelector(el);
  };
  el.addEventListener(event, callback, isCapture);
}
addEvent(document, 'DOMContentLoaded', () => {
  const child = document.querySelector('.child');
  const parent = document.querySelector('.parent');
  const grandparent = document.querySelector('.grandparent');
  addEvent(child, 'click', function (e) {
    console.log('child');
  }, true);
  addEvent(parent, 'click', function (e) {
    console.log('parent');
  }, true);
  addEvent(grandparent, 'click', function (e) {
    console.log('grandparent');
  }, true);
  addEvent(document, 'click', function (e) {
    console.log('document');
  }, true);
  addEvent('html', 'click', function (e) {
    console.log('html');
  }, true)
  addEvent(window, 'click', function (e) {
    console.log('window');
  }, true)
});

Метод addEventListener имеет третий необязательный параметр useCapture со значением по умолчанию false событие произойдет на этапе всплытия, если true событие произойдет на этапе захвата . Если мы нажмем на элемент child, он зарегистрирует window, document, html, grandparent и parent и child соответственно на консоли. Это фиксация событий.

9. В чем разница между методами event.preventDefault() и event.stopPropagation()?

Метод event.preventDefault() предотвращает поведение элемента по умолчанию. Если он используется в элементе form, он предотвращает его отправку. Если он используется в элементе anchor, он предотвращает навигацию по нему. При использовании в contextmenu он предотвращает его отображение или отображение. В то время как метод event.stopPropagation() останавливает распространение события или предотвращает возникновение события на этапе пузырькового или захвата.

10. Как узнать, использовался ли в элементе метод event.preventDefault()?

Мы можем использовать свойство event.defaultPrevented в объекте события. Он возвращает boolean, указывающий, был ли вызван event.preventDefault() в конкретном элементе.

11. Почему этот код obj.someprop.x выдает ошибку?

const obj = {};
console.log(obj.someprop.x);

Очевидно, что это выдает ошибку из-за того, что мы пытаемся получить доступ к свойству
x в свойстве someprop, имеющем значение undefined. Помните, что свойства в объекте, который не существует сам по себе, и его прототип имеет значение по умолчанию undefined, а undefined не имеет свойства x.

12. Что такое event.target?

Проще говоря, event.target — это элемент, для которого произошло событие, или элемент, который инициировал событие.

Пример HTML-разметки.

<div onclick="clickFunc(event)" style="text-align: center;margin:15px;
border:1px solid red;border-radius:3px;">
    <div style="margin: 25px; border:1px solid royalblue;border-radius:3px;">
        <div style="margin:25px;border:1px solid skyblue;border-radius:3px;">
          <button style="margin:10px">
             Button
          </button>
        </div>
    </div>
  </div>

Пример JavaScript.

function clickFunc(event) {
  console.log(event.target);
}

Если вы нажмете кнопку, она зарегистрирует разметку кнопки, даже если мы прикрепим событие к самому внешнему div, она всегда будет записывать кнопку, поэтому мы можем сделать вывод, что event.target — это элемент, вызвавший событие.

13. Что такое event.currentTarget?

event.currentTarget — это элемент, к которому мы прикрепляем обработчик события явно.

Копирование разметки в Вопросе 12.
Пример разметки HTML.

<div onclick="clickFunc(event)" style="text-align: center;margin:15px;
border:1px solid red;border-radius:3px;">
    <div style="margin: 25px; border:1px solid royalblue;border-radius:3px;">
        <div style="margin:25px;border:1px solid skyblue;border-radius:3px;">
          <button style="margin:10px">
             Button
          </button>
        </div>
    </div>
  </div>

И немного изменим наш JS.

function clickFunc(event) {
  console.log(event.currentTarget);
}

Если вы нажмете кнопку, она зарегистрирует самую внешнюю разметку div, даже если мы нажмем кнопку. В этом примере мы можем сделать вывод, что event.currentTarget — это элемент, к которому мы прикрепляем обработчик событий.

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

Разница между ==(абстрактное равенство) и ===(строгое равенство) заключается в том, что == сравнивается по значению после приведения и === сравниваются по значению и типу без принуждения.

Давайте углубимся в ==. Итак, сначала давайте поговорим о принуждении.

приведение — это процесс преобразования значения в другой тип. Как и в этом случае, == выполняет неявное приведение. У == есть несколько условий, которые необходимо выполнить перед сравнением двух значений.

Предположим, нам нужно сравнить x == y значений.

  1. Если x и y имеют одинаковый тип. Затем сравните их с оператором ===.
  2. Если x равно null, а y равно undefined, вернуть true.
  3. Если x равно undefined, а y равно null, вернуть true.
  4. Если x относится к типу number, а y к типу string, то возвращаем x == toNumber(y).
  5. Если x относится к типу string, а y к типу number, то верните toNumber(x) == y.
  6. Если x имеет тип boolean, то вернуть toNumber(x) == y.
  7. Если y имеет тип boolean, то вернуть x == toNumber(y).
  8. Если x равно string, symbol или number, а y имеет тип object, то вернуть x == toPrimitive(y).
  9. Если x равно object, а x равно string, symbol, то вернуть toPrimitive(x) == y.
  10. Вернуть false.

Примечание. toPrimitive сначала использует метод valueOf, а затем метод toString в объектах, чтобы получить примитивное значение этого объекта.

Давайте примеры.

x y x == y 5 5 true 1 '1' true null undefined true 0 false true '1,2' [1,2] true '[object Object]' {} true

Все эти примеры возвращают true.

Первый пример соответствует условию номер один, потому что x и y имеют одинаковый тип и значение.

Второй пример соответствует четвертому условию y перед сравнением преобразуется в number.

Третий пример соответствует второму условию.

Четвертый пример соответствует седьмому условию, потому что y равно boolean.

Пятый пример относится к условию восемь. Массив преобразуется в string с помощью метода toString(), который возвращает 1,2.

Последний пример относится к десятому условию. Объект преобразуется в string с помощью метода toString(), который возвращает [object Object].

x y x === y 5 5 true 1 '1' false null undefined false 0 false false '1,2' [1,2] false '[object Object]' {} false

Если мы используем оператор ===, все сравнения, кроме первого примера, вернут false, потому что они не имеют одного и того же типа, а первый пример вернет true, потому что они имеют одинаковый тип и значение.

15. Почему он возвращает false при сравнении двух похожих объектов в JavaScript?

Допустим, у нас есть пример ниже.

let a = { a: 1 };
let b = { a: 1 };
let c = a;
console.log(a === b); // logs false even though they have the same property
console.log(a === c); // logs true hmm

JavaScript по-разному сравнивает объекты и примитивы. В примитивах они сравниваются по значению, а в объектах сравниваются по ссылке или адресу в память, в которой хранится переменная. Вот почему первый оператор console.log возвращает false, а второй оператор console.log возвращает true. a и c имеют одинаковую ссылку, а a и b - разные.

16. Что означает !! оператор делать?

Оператор Double NOT или !! преобразует значение справа в логическое значение. в основном это причудливый способ преобразования значения в логическое значение.

console.log(!!null); //logs false
console.log(!!undefined); //logs false
console.log(!!''); //logs false
console.log(!!0); //logs false
console.log(!!NaN); //logs false
console.log(!!' '); //logs true
console.log(!!{}); //logs true
console.log(!![]); //logs true
console.log(!!1); //logs true
console.log(!![].length); //logs false

17. Как вычислить несколько выражений в одной строке?

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

let x = 5;
x = (x++ , x = addFive(x), x *= 2, x -= 5, x += 10);
function addFive(num) {
  return num + 5;
}

Если вы запишете значение x, оно будет 27. Во-первых, мы увеличиваем значение x, оно должно быть 6, затем мы вызываем функцию addFive(6) и передаем 6 в качестве параметра и присваиваем результат x новому значению x будет 11. После этого мы умножаем текущее значение x на 2 и назначаем его x обновленное значение x будет 22. Затем мы вычитаем текущее значение x из 5 и присваиваем результат x, обновленное значение будет 17. И, наконец, мы увеличиваем значение x на 10 и присваиваем обновленное значение x, теперь значение x будет 27.

18. Что такое подъем?

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

Хорошо, чтобы понять Поднятие, мне нужно объяснить контекст выполнения.
Контекст выполнения — это «среда кода», которая в настоящее время выполняется. Контекст выполнения состоит из двух фаз: компиляция и выполнение.

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

Выполнение — на этом этапе он присваивает значения переменным, поднятым ранее, и выполняет или вызывает функции (методы в объектах).

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

Хорошо, предположим, что у нас есть пример кода в глобальной области ниже.

console.log(y);
y = 1;
console.log(y);
console.log(greet("Mark"));
function greet(name){
  return 'Hello ' + name + '!';
}
var y;

Этот код регистрирует undefined, 1, Hello Mark! соответственно.

Таким образом, этап компиляции будет выглядеть следующим образом.

function greet(name) {
  return 'Hello ' + name + '!';
}
var y; //implicit "undefined" assignment
//waiting for "compilation" phase to finish
//then start "execution" phase
/*
console.log(y);
y = 1;
console.log(y);
console.log(greet("Mark"));
*/

например, я прокомментировал назначение переменной и вызов функции.

После завершения этапа компиляции начинается этап выполнения, вызывающий методы и присваивающий значения переменным.

function greet(name) {
  return 'Hello ' + name + '!';
}
var y;
//start "execution" phase
console.log(y);
y = 1;
console.log(y);
console.log(greet("Mark"));

19. Что такое объем?

Область в JavaScript — это область, в которой у нас есть действительный доступ к переменным или функциям. В JavaScript есть три типа областей видимости. Глобальная область, Область действия и Область действия блока (ES6).

  • Глобальная область действия — переменные или функции, объявленные в глобальном пространстве имен, находятся в глобальной области видимости и, следовательно, доступны в любом месте нашего кода.
//global namespace
   var g = "global";
   function globalFunc(){
     function innerFunc(){
          console.log(g); // can access "g" because "g" is a global variable
     }
     innerFunc();
   }
  • Область действия — переменные, функции и параметры, объявленные внутри функции, доступны внутри этой функции, но не за ее пределами.
function myFavoriteFunc(a) {
       if (true) {
          var b = "Hello " + a;
       }
       return b;
   }
   myFavoriteFunc("World");
   console.log(a); // Throws a ReferenceError "a" is not defined
   console.log(b); // does not continue here
  • Область блока — переменные (let,const), объявленные в блоке {}, могут быть доступны только внутри него.
function testBlock(){
   if(true){
     let z = 5;
   }
   return z; 
 }
 testBlock(); // Throws a ReferenceError "z" is not defined

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

/* Scope Chain
   Inside inner function perspective
   inner's scope -> outer's scope -> global's scope
  */

  //Global Scope
  var variable1 = "Comrades";   
  var variable2 = "Sayonara";
  function outer(){
  //outer's scope
    var variable1 = "World";
    function inner(){
    //inner's scope
      var variable2 = "Hello";
      console.log(variable2 + " " + variable1);
    }
    inner();
  }  
  outer(); 
// logs Hello World 
// because (variable2 = "Hello") and (variable1 = "World") are the nearest 
// variables inside inner's scope.

20. Что такое замыкания?

Это, наверное, самый сложный вопрос из всех этих вопросов, потому что Замыкания — спорная тема. Поэтому я объясню это из того, что я понимаю.

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

Примеры — отличный способ объяснить замыкания.

//Global's Scope
   var globalVar = "abc";
   function a(){
   //testClosures's Scope
     console.log(globalVar);
   }
   a(); //logs "abc" 
   /* Scope Chain
      Inside a function perspective
      a's scope -> global's scope  
   */

В этом примере, когда мы объявляем функцию a, Global Scope является частью a's замыкания.

Причина, по которой переменная globalVar не имеет значения на изображении из-за того, что значение этой переменной может меняться в зависимости от где и когда мы вызываем a function.
Но в нашем примере выше переменная globalVar будет иметь значение abc.

Хорошо, давайте сложный пример.

var globalVar = "global";
var outerVar = "outer"
function outerFunc(outerParam) {
  function innerFunc(innerParam) {
    console.log(globalVar, outerParam, innerParam);
  }
  return innerFunc;
}
const x = outerFunc(outerVar);
outerVar = "outer-2";
globalVar = "guess"
x("inner");

Это напечатает «угадай внешний внутренний». Объяснение этому заключается в том, что когда мы вызываем функцию outerFunc и присваиваем возвращаемое значение функцией innerFunc переменной x, outerParam будет иметь значение outer, даже если мы назначаем новое значение external-2 в переменную outerVar, потому что
переназначение произошло после вызова функции outer, и в то время, когда мы вызываем функцию outerFunc, она ищет значение outerVar в цепочке областей видимости , outerVar будет иметь значение 'outer'. Теперь, когда мы вызываем переменную x, которая имеет ссылку на innerFunc,
innerParam будет иметь значение inner, потому что это значение, которое мы передаем при вызове, а переменная globalVar будет иметь значение догадка, поскольку перед вызовом переменной x мы присваиваем новое значение globalVar, а во время вызова x значение globalVar в цепочке областей действия равно угадай.

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

const arrFuncs = [];
for(var i = 0; i < 5; i++){
  arrFuncs.push(function (){
    return i;
  });
}
console.log(i); // i is 5
for (let i = 0; i < arrFuncs.length; i++) {
  console.log(arrFuncs[i]()); // all logs "5"
}

Этот код работает не так, как мы ожидали, из-за замыканий.
Ключевое слово var создает глобальную переменную, и когда мы нажимаем функцию,
мы возвращаем глобальную переменную i. Поэтому, когда мы вызываем одну из этих функций в этом массиве после завершения цикла, она регистрирует 5, поскольку мы получаем
текущее значение i, равное 5, и мы можем получить к нему доступ, поскольку это глобальная переменная. Потому что Closures сохраняет ссылки этой переменной, а не ее значения во время ее создания. Мы можем решить эту проблему, используя IIFES или изменив ключевое слово var на let для блочного охвата.

21. Что такое ложные значения в JavaScript?

const falsyValues = ['', 0, null, undefined, NaN, false];

Значения falsy — это значения, которые при преобразовании в логическое значение становятся falsy.

22. Как проверить, является ли значение ложным?

Используйте логическую функцию или оператор двойного НЕ !!

23. Что делает "use strict"?

"use strict" — это функция ES5 в JavaScript, которая переводит наш код в строгий режим в функциях или целых скриптах. . Строгий режим помогает нам избежать ошибок на ранних стадиях нашего кода и добавляет к нему ограничения.

Ограничения, которые накладывает Строгий режим.

  • Назначение или доступ к переменной, которая не объявлена.
function returnY(){
    "use strict";
    y = 123;
    return y;
 }
  • Присвоение значения доступной только для чтения или недоступной для записи глобальной переменной;
"use strict";
   var NaN = NaN;
   var undefined = undefined;
   var Infinity = "and beyond";
  • Удаление неудаляемого свойства.
"use strict";
   const obj = {};
   Object.defineProperty(obj, 'x', {
      value : '1'
   });  
   delete obj.x;
  • Повторяющиеся имена параметров.
"use strict";
   function someFunc(a, b, b, c){
   }
  • Создание переменных с использованием функции eval.
"use strict";
 eval("var x = 1;");
 console.log(x); //Throws a Reference Error x is not defined
  • Значение по умолчанию this будет undefined.
"use strict";
  function showMeThis(){
    return this;
  }
  showMeThis(); //returns undefined

В строгом режиме есть гораздо больше ограничений, чем эти.

24. Каково значение this в JavaScript?

По сути, this относится к значению объекта, который в данный момент выполняет или вызывает функцию. Я говорю в настоящее время по той причине, что значение this меняется в зависимости от контекста, в котором мы его используем, и где мы его используем.

const carDetails = {
     name: "Ford Mustang",
     yearBought: 2005,
     getName(){
        return this.name;
     },
     isRegistered: true
   };
   console.log(carDetails.getName()); // logs Ford Mustang

Это то, что мы обычно ожидаем, потому что в методе getName мы возвращаем this.name, this в этом контексте относится к объекту, который является объектом carDetails, который в настоящее время является объектом-"владельцем" выполняемой функции.

Хорошо, давайте добавим немного кода, чтобы сделать его странным. Под оператором console.log добавьте эти три строки кода

var name = "Ford Ranger";
   var getCarName = carDetails.getName;
   console.log(getCarName()); // logs Ford Ranger

Второй оператор console.log печатает слово Ford Ranger, что странно, потому что в нашем первом операторе console.log было напечатано Ford Mustang. Причина этого в том, что метод getCarName имеет другой объект "владелец", которым является объект window. Объявление переменных с ключевым словом var в глобальной области видимости прикрепляет свойства в объекте window с теми же именами, что и переменные. Помните, что this в глобальной области видимости относится к объекту window, когда "use strict" не используется.

console.log(getCarName === window.getCarName); //logs true
  console.log(getCarName === this.getCarName); // logs true

this и window в этом примере относятся к одному и тому же объекту.

Один из способов решения этой проблемы — использование методов apply и call в функциях.

console.log(getCarName.apply(carDetails)); //logs Ford Mustang
   console.log(getCarName.call(carDetails));  //logs Ford Mustang

Методы apply и call предполагают, что первым параметром будет объект, который будет иметь значение this внутри этой функции.

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

(function (){
     console.log(this);
   })(); //logs the "window" object
   function iHateThis(){
      console.log(this);
   }
   iHateThis(); //logs the "window" object  
   const myFavoriteObj = {
     guessThis(){
        function getThis(){
          console.log(this);
        }
        getThis();
     },
     name: 'Marko Polo',
     thisIsAnnoying(callback){
       callback();
     }
   };

   myFavoriteObj.guessThis(); //logs the "window" object
   myFavoriteObj.thisIsAnnoying(function (){
     console.log(this); //logs the "window" object
   });

Если мы хотим получить значение свойства name, которое является Marko Polo в объекте myFavoriteObj, есть два способа решить эту проблему.

Сначала мы сохраняем значение this в переменной.

const myFavoriteObj = {
     guessThis(){
         const self = this; //saves the this value to the "self" variable
         function getName(){
           console.log(self.name);
         }
         getName();
     },
     name: 'Marko Polo',
     thisIsAnnoying(callback){
       callback();
     }
   };

В этом изображении мы сохраняем значение this, которое будет объектом myFavoriteObj. Таким образом, мы можем получить к нему доступ внутри внутренней функции getName.

Во-вторых, мы используем ES6 Стрелочные функции.

const myFavoriteObj = {
     guessThis(){
         const getName = () => { 
           //copies the value of "this" outside of this arrow function
           console.log(this.name);
         }
         getName();
     },
     name: 'Marko Polo',
     thisIsAnnoying(callback){
       callback();
     }
   };

Стрелочные функции не имеют своего this. Он копирует значение this объемлющей лексической области или, в этом примере, значение this вне внутренней функции getName, которая будет объектом myFavoriteObj. Мы также можем определить значение this по тому, как вызывается функция.

25. Что такое prototype объекта?

Проще говоря, prototype — это чертеж объекта. Он используется в качестве запасного варианта для свойств и методов, если он существует в текущем объекте. Это способ совместного использования свойств и функций между объектами. Это основная концепция прототипного наследования в JavaScript.

const o = {};
  console.log(o.toString()); // logs [object Object]

Несмотря на то, что метод o.toString не существует в объекте o, он не выдает ошибку, а возвращает строку [object Object]. Когда свойство не существует в объекте, оно ищет его прототип, а если оно все еще не существует, оно ищет прототип прототипа и так далее, пока не найдет свойство с то же самое в цепочке прототипов. Концом цепочки прототипов является Object.prototype.

console.log(o.toString === Object.prototype.toString); // logs true
   // which means we we're looking up the Prototype Chain and it reached 
   // the Object.prototype and used the "toString" method.

26. Что такое IIFE, какая от него польза?

IIFE или Выражение немедленно вызываемой функции — это функция, которая будет вызываться или выполняться после ее создания или объявления. Синтаксис для создания IIFE заключается в том, что мы заключаем function (){} в круглые скобки () или оператор группировки для обработки функции как выражения, а после этого мы вызываем ее с другими круглыми скобками () . Итак, IIFE выглядит так (function(){})().

(function () {
}());
(function () {
})();
(function named(params) {
})();
(() => {
})();
(function (global) {
})(window);
const utility = (function () {
   return {
      //utilities
   };
})();

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

Наилучшее использование IIFE — создание функций настройки инициализации и избежание конфликтов имен с другими переменными в глобальной области видимости или загрязнения глобального пространства имен. Давайте рассмотрим пример.

<script src="https://cdnurl.com/somelibrary.js"></script>

Предположим, у нас есть ссылка на библиотеку somelibrary.js, которая предоставляет некоторые глобальные функции, которые мы можем использовать в нашем коде, но в этой библиотеке есть два метода, которые мы не используем, createGraph и drawGraph, потому что в этих методах есть ошибки. И мы хотим реализовать собственные методы createGraph и drawGraph.

  • Один из способов решить эту проблему — изменить структуру наших скриптов.
<script src="https://cdnurl.com/somelibrary.js"></script>
<script>
   function createGraph() {
      // createGraph logic here
   }
   function drawGraph() {
      // drawGraph logic here
   }
</script>

Когда мы используем это решение, мы переопределяем те два метода, которые дает нам библиотека.

  • Другой способ решить эту проблему — изменить имя наших собственных вспомогательных функций.
<script src="https://cdnurl.com/somelibrary.js"></script>
<script>
   function myCreateGraph() {
      // createGraph logic here
   }
   function myDrawGraph() {
      // drawGraph logic here
   }
</script>

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

  • Другой способ — использовать IIFE.
<script src="https://cdnurl.com/somelibrary.js"></script>
<script>
   const graphUtility = (function () {
      function createGraph() {
         // createGraph logic here
      }
      function drawGraph() {
         // drawGraph logic here
      }
      return {
         createGraph,
         drawGraph
      }
   })();
</script>

В этом решении мы создаем служебную переменную, являющуюся результатом IIFE, которая возвращает объект, содержащий два метода createGraph и drawGraph.

Еще одна проблема, которую решает IIFE, представлена ​​в этом примере.

var li = document.querySelectorAll('.list-group > li');
for (var i = 0, len = li.length; i < len; i++) {
   li[i].addEventListener('click', function (e) {
      console.log(i);
   })
}

Предположим, у нас есть элемент ul с классом list-group и у него есть 5 дочерних элементов li. И мы хотим console.log значение i, когда мы щелкаем отдельный элемент li.
Но поведение, которое мы хотим в этом коде, не работает. Вместо этого он регистрирует 5 при каждом нажатии элемента li. Наша проблема связана с тем, как работают замыкания. Замыкания — это просто способность функций запоминать ссылки на переменные в своей текущей области, в области родительской функции и в глобальной области. Когда мы объявляем переменные с помощью ключевого слова var в глобальной области видимости, очевидно, мы создаем глобальную переменную i. Поэтому, когда мы щелкаем элемент li, он регистрирует 5, потому что это значение i, когда мы ссылаемся на него позже в функции обратного вызова.

  • Одним из решений этой проблемы является IIFE.
var li = document.querySelectorAll('.list-group > li');
for (var i = 0, len = li.length; i < len; i++) {
   (function (currentIndex) {
      li[currentIndex].addEventListener('click', function (e) {
         console.log(currentIndex);
      })
   })(i);
}

Это решение работает по той причине, что IIFE создает новую область для каждой итерации, и мы фиксируем значение i и передаем его в параметр currentIndex, поэтому значение currentIndex отличается для каждой итерации, когда мы вызвать IIFE.

27. Что такое метод использования Function.prototype.apply?

apply вызывает функцию, определяющую this или объект владельца этой функции в момент вызова.

const details = {
  message: 'Hello World!'
};
function getMessage(){
  return this.message;
}
getMessage.apply(details); // returns 'Hello World!'

Этот метод работает как Function.prototype.call с той лишь разницей, как мы передаем аргументы. В apply мы передаем аргументы в виде массива.

const person = {
  name: "Marko Polo"
};
function greeting(greetingMessage) {
  return `${greetingMessage} ${this.name}`;
}
greeting.apply(person, ['Hello']); // returns "Hello Marko Polo!"

28. Что такое метод использования Function.prototype.call?

call вызывает функцию, определяющую this или объект владельца этой функции в момент вызова.

const details = {
  message: 'Hello World!'
};
function getMessage(){
  return this.message;
}
getMessage.call(details); // returns 'Hello World!'

Этот метод работает как Function.prototype.apply с той лишь разницей, как мы передаем аргументы. В call мы передаем непосредственно аргументы, разделяя их запятой , для каждого аргумента.

const person = {
  name: "Marko Polo"
};
function greeting(greetingMessage) {
  return `${greetingMessage} ${this.name}`;
}
greeting.call(person, 'Hello'); // returns "Hello Marko Polo!"

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

Единственная разница между apply и call заключается в том, как мы передаем аргументы в вызываемую функцию. В apply мы передаем аргументы в виде массива, а в call мы передаем аргументы непосредственно в списке аргументов.

const obj1 = {
 result:0
};
const obj2 = {
 result:0
};
function reduceAdd(){
   let result = 0;
   for(let i = 0, len = arguments.length; i < len; i++){
     result += arguments[i];
   }
   this.result = result;
}
reduceAdd.apply(obj1, [1, 2, 3, 4, 5]); // returns 15
reduceAdd.call(obj2, 1, 2, 3, 4, 5); // returns 15

30. Каково использование Function.prototype.bind?

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

import React from 'react';
class MyComponent extends React.Component {
     constructor(props){
          super(props); 
          this.state = {
             value : ""
          }  
          this.handleChange = this.handleChange.bind(this); 
          // Binds the "handleChange" method to the "MyComponent" component
     }
     handleChange(e){
       //do something amazing here
     }
     render(){
        return (
              <>
                <input type={this.props.type}
                        value={this.state.value}
                     onChange={this.handleChange}                      
                  />
              </>
        )
     }
}

31. Что такое функциональное программирование и какие особенности JavaScript делают его кандидатом в качестве функционального языка?

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

JavaScript Array имеет методы map, filter, reduce, которые являются самыми известными функциями в мире функционального программирования из-за их полезности, а также потому, что они не мутируют и не изменяют массив, что делает эти функции чистыми, а JavaScript поддерживает замыкания и функции высшего порядка, которые являются характеристика функционального языка программирования.

  • Метод map создает новый массив с результатами вызова предоставленной функции обратного вызова для каждого элемента массива.
const words = ["Functional", "Procedural", "Object-Oriented"];
const wordsLength = words.map(word => word.length);
  • Метод filter создает новый массив со всеми элементами, прошедшими проверку в функции обратного вызова.
const data = [
  { name: 'Mark', isRegistered: true },
  { name: 'Mary', isRegistered: false },
  { name: 'Mae', isRegistered: true }
];
const registeredUsers = data.filter(user => user.isRegistered);
  • Метод reduce применяет функцию к аккумулятору и каждому элементу массива (слева направо), чтобы уменьшить его до одного значения.
const strs = ["I", " ", "am", " ", "Iron", " ", "Man"];
const result = strs.reduce((acc, currentStr) => acc + currentStr, "");

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

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

function higherOrderFunction(param,callback){
    return callback(param);
}

33. Почему функции называются объектами первого класса?

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

34. Реализуйте метод Array.prototype.map вручную.

function map(arr, mapCallback) {
  // First, we check if the parameters passed are right.
  if (!Array.isArray(arr) || !arr.length || typeof mapCallback !== 'function') { 
    return [];
  } else {
    let result = [];
    // We're making a results array every time we call this function
    // because we don't want to mutate the original array.
    for (let i = 0, len = arr.length; i < len; i++) {
      result.push(mapCallback(arr[i], i, arr)); 
      // push the result of the mapCallback in the 'result' array
    }
    return result; // return the result array
  }
}

Как описание MDN метода Array.prototype.map.

Метод map() создает новый массив с результатами вызова предоставленной функции для каждого элемента в вызывающем массиве.

35. Реализуйте метод Array.prototype.filter вручную.

function filter(arr, filterCallback) {
  // First, we check if the parameters passed are right.
  if (!Array.isArray(arr) || !arr.length || typeof filterCallback !== 'function') 
  {
    return [];
  } else {
    let result = [];
    // We're making a results array every time we call this function
    // because we don't want to mutate the original array.
    for (let i = 0, len = arr.length; i < len; i++) {
      // check if the return value of the filterCallback is true or "truthy"
      if (filterCallback(arr[i], i, arr)) { 
      // push the current item in the 'result' array if the condition is true
        result.push(arr[i]);
      }
    }
    return result; // return the result array
  }
}

Как описание MDN метода Array.prototype.filter.

Метод filter() создает новый массив со всеми элементами, прошедшими проверку, реализованную предоставленной функцией.

36. Реализуйте метод Array.prototype.reduce вручную.

function reduce(arr, reduceCallback, initialValue) {
  // First, we check if the parameters passed are right.
  if (!Array.isArray(arr) || !arr.length || typeof reduceCallback !== 'function') 
  {
    return [];
  } else {
    // If no initialValue has been passed to the function we're gonna use the 
    let hasInitialValue = initialValue !== undefined;
    let value = hasInitialValue ? initialValue : arr[0];
    // first array item as the initialValue
    // Then we're gonna start looping at index 1 if there is no 
    // initialValue has been passed to the function else we start at 0 if 
    // there is an initialValue.
    for (let i = hasInitialValue ? 0 : 1, len = arr.length; i < len; i++) {
      // Then for every iteration we assign the result of the 
      // reduceCallback to the variable value.
      value = reduceCallback(value, arr[i], i, arr); 
    }
    return value;
  }
}

В качестве описания MDN метода Array.prototype.reduce.

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

37. Что такое объект arguments?

Объект arguments представляет собой набор значений параметров, передаваемых в функцию. Это подобный массиву объект, поскольку он имеет свойство length, и мы можем получить доступ к отдельным значениям, используя нотацию индексации массива arguments[1], но у него нет встроенных методов в массиве. forEach,reduce, filter и map.
Это помогает нам узнать количество аргументов, передаваемых в функцию.

Мы можем преобразовать объект arguments в массив, используя метод Array.prototype.slice.

function one() {
  return Array.prototype.slice.call(arguments);
}

Примечание: объект arguments не работает со стрелочными функциями ES6.

function one() {
  return arguments;
}
const two = function () {
  return arguments;
}
const three = function three() {
  return arguments;
}
const four = () => arguments;
four(); // Throws an error  - arguments is not defined

Когда мы вызываем функцию four, она выдает ошибку ReferenceError: arguments is not defined. Мы можем решить эту проблему, если ваша среда поддерживает остальный синтаксис.

const four = (...args) => args;

Это автоматически помещает все значения параметров в массив.

38. Как создать объект без прототипа?

Мы можем создать объект без прототипа, используя метод Object.create.

const o1 = {};
   console.log(o1.toString()); 
   // logs [object Object] get this method to the Object.prototype 
   const o2 = Object.create(null);
   // the first parameter is the prototype of the object "o2" which in this
   // case will be null specifying we don't want any prototype
   console.log(o2.toString());
   // throws an error o2.toString is not a function

39. Почему b в этом коде становится глобальной переменной при вызове этой функции?

function myFunc() {
  let a = b = 0;
}
myFunc();

Причина этого в том, что оператор присваивания или = имеет ассоциативность справа налево или оценку. Это означает, что когда в одном выражении появляется несколько операторов присваивания, они оцениваются справа налево. Итак, наш код становится таким.

function myFunc() {
  let a = (b = 0);
}
myFunc();

Во-первых, вычислено выражение b = 0, а в этом примере b не объявлено. Таким образом, JS Engine создает глобальную переменную b вне этой функции, после чего возвращаемое значение выражения b = 0 будет равно 0, и оно присваивается новой локальной переменной a с ключевым словом let.

Мы можем решить эту проблему, сначала объявив переменные, прежде чем присваивать им значение.

function myFunc() {
  let a,b;
  a = b = 0;
}
myFunc();

40. Что такое ECMAScript?

ECMAScript — это стандарт для создания языков сценариев, что означает, что JavaScript следует изменениям спецификации в стандарте ECMAScript, поскольку он схема JavaScript.

41. Какие новые функции появились в ES6 или ECMAScript 2015?

42. В чем разница между ключевыми словами var, let и const?

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

function giveMeX(showX) {
  if (showX) {
    var x = 5;
  }
  return x;
}
console.log(giveMeX(false));
console.log(giveMeX(true));

Первый оператор console.log регистрирует undefined
, а второй 5. Мы можем получить доступ к переменной x из-за
того, что она поднята вверху области действия функции. Таким образом, наш код функции интерпретируется следующим образом.

function giveMeX(showX) {
  var x; // has a default value of undefined
  if (showX) {
    x = 5;
  }
  return x;
}

Если вам интересно, почему он записывает undefined в первый оператор console.log, помните, что переменные, объявленные без начального значения, имеют значение по умолчанию undefined.

Переменные, объявленные с помощью ключевых слов let и const, имеют блочную область действия. Что это означает, что доступ к переменной возможен только в том блоке {}, где мы ее объявляем.

function giveMeX(showX) {
  if (showX) {
    let x = 5;
  }
  return x;
}

function giveMeY(showY) {
  if (showY) {
    let y = 5;
  }
  return y;
}

Если мы вызовем эту функцию с аргументом false, она выдаст Reference Error, потому что мы не можем получить доступ к переменным x и y вне этого блока, и эти переменные не подняты.

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

43. Что такое стрелочные функции?

Стрелочные функции — это новый способ создания функций в JavaScript. Функции со стрелками требуют немного времени для создания функций и имеют более чистый синтаксис, чем функциональное выражение, поскольку при их создании мы опускаем ключевое слово function.

//ES5 Version
var getCurrentDate = function (){
  return new Date();
}
//ES6 Version
const getCurrentDate = () => new Date();

В этом примере в версии ES5 есть объявление function(){} и ключевое слово return, необходимые для создания функции и возврата значения соответственно. В версии Стрелочная функция нам нужны только круглые скобки (), и нам не нужен оператор return, потому что стрелочные функции имеют неявный возврат, если у нас есть только одно выражение или значение для возвращаться.

//ES5 Version
function greet(name) {
  return 'Hello ' + name + '!';
}
//ES6 Version
const greet = (name) => `Hello ${name}`;
const greet2 = name => `Hello ${name}`;

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

const getArgs = () => arguments
const getArgs2 = (...rest) => rest

Функции со стрелками не имеют доступа к объекту arguments. Таким образом, вызов первой функции getArgs вызовет ошибку. Вместо этого мы можем использовать остальные параметры, чтобы получить все аргументы, переданные в стрелочную функцию.

const data = {
  result: 0,
  nums: [1, 2, 3, 4, 5],
  computeResult() {
    // "this" here refers to the "data" object
    const addAll = () => {
      // arrow functions "copies" the "this" value of 
      // the lexical enclosing function
      return this.nums.reduce((total, cur) => total + cur, 0)
    };
    this.result = addAll();
  }
};

Функции со стрелками не имеют собственного значения this. Он захватывает или получает значение this лексически объемлющей функции, или в этом примере функция addAll копирует значение this метода computeResult, и если мы объявим стрелочную функцию в глобальной области видимости, значением this будет объект window.

44. Что такое классы?

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

//ES5 Version
   function Person(firstName, lastName, age, address){
      this.firstName = firstName;
      this.lastName = lastName;
      this.age = age;
      this.address = address;
   }
   Person.self = function(){
     return this;
   }
   Person.prototype.toString = function(){
     return "[object Person]";
   }
   Person.prototype.getFullName = function (){
     return this.firstName + " " + this.lastName;
   }  
   //ES6 Version
   class Person {
        constructor(firstName, lastName, age, address){
            this.lastName = lastName;
            this.firstName = firstName;
            this.age = age;
            this.address = address;
        }
        static self() {
           return this;
        }
        toString(){
           return "[object Person]";
        }
        getFullName(){
           return `${this.firstName} ${this.lastName}`;
        }
   }

Переопределение методов и Наследование от другого класса.

//ES5 Version
Employee.prototype = Object.create(Person.prototype);
function Employee(firstName, lastName, age, address, jobTitle, yearStarted) {
  Person.call(this, firstName, lastName, age, address);
  this.jobTitle = jobTitle;
  this.yearStarted = yearStarted;
}
Employee.prototype.describe = function () {
  return `I am ${this.getFullName()} and I have a position of ${this.jobTitle} and I started at ${this.yearStarted}`;
}
Employee.prototype.toString = function () {
  return "[object Employee]";
}
//ES6 Version
class Employee extends Person { //Inherits from "Person" class
  constructor(firstName, lastName, age, address, jobTitle, yearStarted) {
    super(firstName, lastName, age, address);
    this.jobTitle = jobTitle;
    this.yearStarted = yearStarted;
  }
  describe() {
    return `I am ${this.getFullName()} and I have a position of ${this.jobTitle} and I started at ${this.yearStarted}`;
  }
  toString() { // Overriding the "toString" method of "Person"
    return "[object Employee]";
  }
}

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

class Something {
   }
   function AnotherSomething(){
   }
   const as = new AnotherSomething();
   const s = new Something();
   console.log(typeof Something); // logs "function"
   console.log(typeof AnotherSomething); // logs "function"
   console.log(as.toString()); // logs "[object Object]"
   console.log(as.toString()); // logs "[object Object]"
   console.log(as.toString === Object.prototype.toString); 
   console.log(s.toString === Object.prototype.toString); 
   // both logs return true indicating that we are still using 
   // prototypes under the hoods because the Object.prototype is
   // the last part of the Prototype Chain and "Something"
   // and "AnotherSomething" both inherit from Object.prototype

45. Что такое шаблонные литералы?

Литералы шаблонов — это новый способ создания строк в JavaScript. Мы можем сделать Template Literal, используя символ обратной кавычки или обратной кавычки.

//ES5 Version
var greet = 'Hi I\'m Mark';
//ES6 Version
let greet = `Hi I'm Mark`;

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

//ES5 Version
var lastWords = '\n'
  + '   I  \n'
  + '   Am  \n'
  + 'Iron Man \n';

//ES6 Version
let lastWords = `
    I
    Am
  Iron Man   
`;

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

//ES5 Version
function greet(name) {
  return 'Hello ' + name + '!';
}

//ES6 Version
const greet = name => {
  return `Hello ${name} !`;
}

В версии ES5, если нам нужно добавить выражение или значение в строку, нам нужно использовать + или оператор конкатенации строк. В шаблонных литералах мы можем встроить выражение, используя ${expr}, что делает его чище, чем версия ES5.

46. ​​Что такое деструктуризация объекта?

Деструктуризация объектов — это новый и более понятный способ получения или извлечения значений из объекта или массива.

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

const employee = {
  firstName: "Marko",
  lastName: "Polo",
  position: "Software Developer",
  yearHired: 2017
};

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

var firstName = employee.firstName;
var lastName = employee.lastName;
var position = employee.position;
var yearHired = employee.yearHired;

Если мы используем деструктурирование объектов, это выглядит чище и занимает немного времени, чем старый способ. Синтаксис деструктуризации объекта заключается в том, что если мы получаем свойства объекта, мы используем {}, а внутри него мы указываем свойства, которые хотим извлечь, и если мы получаем данные из массива, мы используем [].

let { firstName, lastName, position, yearHired } = employee;

Если мы хотим изменить имя переменной, которую мы хотим извлечь, мы используем синтаксис propertyName:newName. В этом примере значение переменной fName будет содержать значение свойства firstName, а переменная lName будет содержать значение свойства lastName.

let { firstName: fName, lastName: lName, position, yearHired } = employee;

У нас также могут быть значения по умолчанию при деструктуризации. В этом примере, если свойство firstName содержит значение undefined в объекте, то при деструктуризации переменная firstName будет содержать значение по умолчанию "Mark".

let { firstName = "Mark", lastName: lName, position, yearHired } = employee;

47. Что такое ES6 Modules?

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

  • CommonJS — Nodejs
  • AMD (определение асинхронного модуля) — Браузеры

По сути, синтаксис для использования модулей прост:
import используется для получения функций из другого файла или нескольких функций или значений, а
export используется для представления функциональность из файла или несколько функций или значений.

Экспорт функциональных возможностей в файл или именованный экспорт

Использование ES5 (CommonJS)

// Using ES5 CommonJS - helpers.js
exports.isNull = function (val) {
  return val === null;
}
exports.isUndefined = function (val) {
  return val === undefined;
}
exports.isNullOrUndefined = function (val) {
  return exports.isNull(val) || exports.isUndefined(val);
}

Использование модулей ES6

// Using ES6 Modules - helpers.js
export function isNull(val){
  return val === null;
}
export function isUndefined(val) {
  return val === undefined;
}
export function isNullOrUndefined(val) {
  return isNull(val) || isUndefined(val);
}

Импорт функциональных возможностей в другой файл

// Using ES5 (CommonJS) - index.js
const helpers = require('./helpers.js'); // helpers is an object
const isNull = helpers.isNull;
const isUndefined = helpers.isUndefined;
const isNullOrUndefined = helpers.isNullOrUndefined;
// or if your environment supports Destructuring
const { isNull, isUndefined, isNullOrUndefined } = require('./helpers.js');
// ES6 Modules - index.js
import * as helpers from './helpers.js'; // helpers is an object
// or 
import { isNull, isUndefined, isNullOrUndefined as isValid } from './helpers.js';
// using "as" for renaming named exports

Экспорт одной функции в файл или экспорт по умолчанию

Использование ES5 (CommonJS)

// Using ES5 (CommonJS) - index.js
class Helpers {
  static isNull(val) {
    return val === null;
  }
  static isUndefined(val) {
    return val === undefined;
  }
  static isNullOrUndefined(val) {
    return this.isNull(val) || this.isUndefined(val);
  }
}

module.exports = Helpers;

Использование модулей ES6

// Using ES6 Modules - helpers.js
class Helpers {
  static isNull(val) {
    return val === null;
  }
  static isUndefined(val) {
    return val === undefined;
  }
  static isNullOrUndefined(val) {
    return this.isNull(val) || this.isUndefined(val);
  }
}
export default Helpers

Импорт одной функции из другого файла

Использование ES5 (CommonJS)

// Using ES5 (CommonJS) - index.js
const Helpers = require('./helpers.js'); 
console.log(Helpers.isNull(null));

Использование модулей ES6

import Helpers from '.helpers.js'
console.log(Helpers.isNull(null));

Это основы использования модулей ES6. Я не буду объяснять все о модулях, потому что это широкая тема, а мой пост теперь очень длинный.

48. Что такое объект Set и как он работает?

Объект Set — это функция ES6, которая позволяет хранить уникальные значения, примитивы или ссылки на объекты. Значение в наборе может встречаться только один раз. Он проверяет, существует ли значение в заданном объекте, используя алгоритм SameValueZero.

Мы можем создать экземпляр Set, используя конструктор Set, и при желании можем передать Iterable в качестве начального значения.

const set1 = new Set();
const set2 = new Set(["a","b","c","d","d","e"]);

Мы можем добавить новое значение в экземпляр Set, используя метод add, и поскольку add возвращает объект Set, мы можем сцепить вызовы add. Если значение уже существует в объекте Set, оно не будет добавлено снова.

set2.add("f");
set2.add("g").add("h").add("i").add("j").add("k").add("k");
// the last "k" will not be added to the set object because it already exists

Мы можем удалить значение из экземпляра Set с помощью метода delete, этот метод возвращает boolean, указывающий true, если значение существует в объекте Set, и false, указывающий, что значение не существует.

set2.delete("k") // returns true because "k" exists in the set object
set2.delete("z") // returns false because "z" does not exists in the set object

Мы можем проверить, существует ли конкретное значение в экземпляре Set, используя метод has.

set2.has("a") // returns true because "a" exists in the set object
set2.has("z") // returns false because "z" does not exists in the set object

Мы можем получить длину экземпляра Set, используя свойство size.

set2.size // returns 10

Мы можем удалить или удалить все элементы экземпляра Set, используя файл clear.

set2.clear(); // clears the set data

Мы можем использовать объект Set для удаления повторяющихся элементов в массиве.

const numbers = [1, 2, 3, 4, 5, 6, 6, 7, 8, 8, 5];
const uniqueNums = [...new Set(numbers)]; // has a value of [1,2,3,4,5,6,7,8]

49. Что такое функция обратного вызова?

Функция обратного вызова — это функция, которая будет вызвана позже.

const btnAdd = document.getElementById('btnAdd');
btnAdd.addEventListener('click', function clickCallback(e) {
    // do something useless
});

В этом примере мы ждем click event в элементе с идентификатором btnAdd, если это clicked, выполняется функция clickCallback. Функция Обратный вызов добавляет некоторую функциональность к некоторым данным или событию. Методы reduce, filter и map в Array ожидают обратного вызова в качестве параметра. Хорошая аналогия для обратного звонка: вы звоните кому-то, и если они не отвечают, вы оставляете сообщение и ожидаете, что они перезвонят. Звонок кому-либо или оставление сообщения – это событие или данные, а обратный вызов – это действие, которое вы ожидаете позже. .

50. Что такое обещания?

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

fs.readFile('somefile.txt', function (e, data) {
  if (e) {
    console.log(e);
  }
  console.log(data);
});

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

//Callback Hell yucksss
fs.readFile('somefile.txt', function (e, data) {
  //your code here
  fs.readdir('directory', function (e, files) {
    //your code here
    fs.mkdir('directory', function (e) {
      //your code here
    })
  })
})

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

promReadFile('file/path')
  .then(data => {
    return promReaddir('directory');
  })
  .then(data => {
    return promMkdir('directory');
  })
  .catch(e => {
    console.log(e);
  })

Обещания имеют 3 разных состояния.

Ожидание — начальное состояние промиса. Результат обещания еще не известен, потому что операция еще не завершена.

Выполнено — асинхронная операция завершена и выполнена успешно с результирующим значением.

Отклонено — асинхронная операция завершилась неудачно, и есть причина, почему она не удалась.

Урегулировано — если обещание было выполнено или отклонено.

Конструктор Promise имеет два параметра, которые являются функциями resolve и reject соответственно.
Если асинхронная операция была завершена без ошибок, вызовите функцию resolve для разрешения обещания или если произошла ошибка
вызвать функцию reject и передать ей ошибку или причину.
Мы можем получить доступ к результату выполненного обещания с помощью метода .then
и отловить ошибки в методе .catch. Мы объединяем несколько асинхронных операций обещания в методе .then, потому что метод .then возвращает Promise, как в примере на изображении выше.

const myPromiseAsync = (...args) => {
  return new Promise((resolve, reject) => {
    doSomeAsync(...args, (error, data) => {
      if (error) {
        reject(error);
      } else {
        resolve(data);
      }
    })
  })
}
myPromiseAsync()
  .then(result => {
    console.log(result);
  })
  .catch(reason => {
    console.log(reason);
  })

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

const toPromise = (asyncFuncWithCallback) => {
  return (...args) => {
    return new Promise((res, rej) => {
      asyncFuncWithCallback(...args, (e, result) => {
        return e ? rej(e) : res(result);
      });
    });
  }
}
const promReadFile = toPromise(fs.readFile);
promReadFile('file/path')
  .then((data) => {
    console.log(data);
  })
  .catch(e => console.log(e));

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

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

Использование обещаний.

function callApi() {
  return fetch("url/to/api/endpoint")
    .then(resp => resp.json())
    .then(data => {
      //do something with "data"
    }).catch(err => {
      //do something with "err"
    });
}

Использование асинхронного/ожидания.

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

async function callApi() {
  try {
    const resp = await fetch("url/to/api/endpoint");
    const data = await resp.json();
    //do something with "data"
  } catch (e) {
    //do something with "err"
  }
}

Примечание. Ключевое слово async перед объявлением функции заставляет функцию неявно возвращать обещание.

const giveMeOne = async () => 1;
giveMeOne()
  .then((num) => {
    console.log(num); // logs 1
  });

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

const giveMeOne = async () => 1;
function getOne() {
  try {
    const num = await giveMeOne();
    console.log(num);
  } catch (e) {
    console.log(e);
  }
}
//Throws a Compile-Time Error = Uncaught SyntaxError: await is only valid in an async function
async function getTwo() {
  try {
    const num1 = await giveMeOne(); //finishes this async operation first before going to
    const num2 = await giveMeOne(); //this line
    return num1 + num2;
  } catch (e) {
    console.log(e);
  }
}
await getTwo(); // returns 2

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

Оператор Spread и параметры Rest имеют один и тот же оператор ..., разница между ними заключается в том, что оператор Spread мы задаем. strong> или распространить отдельные данные массива на другие данные, в то время как остальные параметры используются в функции или массиве для получения всех аргументов или значения и поместить их в массив или извлечь некоторые из них.

function add(a, b) {
  return a + b;
};
const nums = [5, 6];
const sum = add(...nums);
console.log(sum);

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

function add(...rest) {
  return rest.reduce((total,current) => total + current);
};
console.log(add(1, 2)); // logs 3
console.log(add(1, 2, 3, 4, 5)); // logs 15

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

const [first, ...others] = [1, 2, 3, 4, 5];
console.log(first); //logs 1
console.log(others); //logs [2,3,4,5]

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

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

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

//ES5 Version
function add(a,b){
  a = a || 0;
  b = b || 0;
  return a + b;
}
//ES6 Version
function add(a = 0, b = 0){
  return a + b;
}
//If we don't pass any argument for 'a' or 'b' then 
// it's gonna use the "default parameter" value which is 0
add(1); // returns 1

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

function getFirst([first, ...rest] = [0, 1]) {
  return first;
}
getFirst();  // returns 0
getFirst([10,20,30]);  // returns 10
function getArr({ nums } = { nums: [1, 2, 3, 4] }){
    return nums;
}
getArr(); // returns [1, 2, 3, 4]
getArr({nums:[5,4,3,2,1]}); // returns [5,4,3,2,1]

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

function doSomethingWithValue(value = "Hello World", callback = () => { console.log(value) }) {
  callback();
}
doSomethingWithValue(); //logs "Hello World"

54. Что такое объекты-оболочки?

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

let name = "marko";
console.log(typeof name); // logs  "string"
console.log(name.toUpperCase()); // logs  "MARKO"

name — это значение primitive string, не имеющее свойств и методов, но в этом примере мы вызываем метод toUpperCase(), который не выдает ошибку, а возвращает MARKO.

Причина этого в том, что значение primitive временно преобразуется или принуждается к object, поэтому переменная name ведет себя как object. Все primitive, кроме null и undefined, имеют объекты-оболочки. Объекты-оболочки: String, Number, Boolean, Symbol и BigInt. В данном случае вызов name.toUpperCase() за кадром выглядит так.

console.log(new String(name).toUpperCase()); // logs  "MARKO"

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

55. В чем разница между неявным и явным принуждением?

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

Предположим, у нас есть пример ниже.

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

Первая инструкция console.log регистрирует 16. В других языках это вызовет ошибку времени компиляции, но в JavaScript 1 преобразуется в string, а затем объединяется с оператором +. Мы ничего не делали, но он был автоматически конвертирован для нас с помощью JavaScript.
Второй оператор console.log регистрирует 1, он преобразует false в boolean, что приводит к 0, а true будет 1, следовательно, результат 1.
Третий оператор console.log регистрирует 12, он преобразует '2' в number перед умножением 6 * 2, следовательно, результат 12.
Правила приведения JavaScript

В то время как явное приведение — это способ преобразования значений в другой тип, когда мы (программисты) явно делаем это.

console.log(1 + parseInt('6'));

В этом примере мы используем функцию parseInt для преобразования '6' в number, а затем добавляем 1 и 6 с помощью оператора +.

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

NaN означает, что 'Not A Number' — это значение в JavaScript, которое является результатом преобразования или выполнения операции с числом в нечисловое значение, следовательно, приводит к NaN.

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, который проверяет, является ли значение isNaN значением. Но эта функция имеет странное поведение.

console.log(isNaN()); //logs true
console.log(isNaN(undefined)); //logs true
console.log(isNaN({})); //logs true
console.log(isNaN(String('a'))); //logs true
console.log(isNaN(() => { })); //logs true

Все эти операторы console.log возвращают true, несмотря на то, что переданные нами значения не являются NaN.

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

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

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

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

console.log(Array.isArray(5));  //logs false
console.log(Array.isArray("")); //logs false
console.log(Array.isArray()); //logs false
console.log(Array.isArray(null)); //logs false
console.log(Array.isArray({ length: 5 })); //logs false
console.log(Array.isArray([])); //logs true

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

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

58. Как проверить, является ли число четным, не используя оператор % или по модулю?

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

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

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

101 & 001 101 001 001

  • Итак, сначала мы сравниваем самый левый бит 1&0, результат должен быть 0.
  • Затем сравниваем средний бит 0&0 результат должен быть 0.
  • Затем мы сравниваем последний бит 1&1, результат должен быть 1.
  • Затем двоичный результат 001 будет преобразован в десятичное число, которое будет 1.

Если мы console.log это выражение 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); //This logs true indicating the property "prop" is in "o" object
console.log("prop1" in o); //This logs false indicating the property "prop" is not in  "o" object

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

//Still using the o object in the first example.
console.log(o.hasOwnProperty("prop2")); // This logs true
console.log(o.hasOwnProperty("prop1")); // This logs false

В-третьих, используя обозначение в скобках obj["prop"]. Если свойство существует, оно возвращает значение этого свойства, в противном случае будет возвращено undefined.

//Still using the o object in the first example.
console.log(o["prop"]); // This logs "bwahahah"
console.log(o["prop1"]); // This logs undefined

60. Что такое АЯКС?

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

Технологии, используемые для AJAX.

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

61. Какие есть способы создания объектов в JavaScript?

Использование Object Literal.

const o = {
   name: "Mark",
   greeting() {
      return `Hi, I'm ${this.name}`;
   }
  };
  o.greeting(); //returns "Hi, I'm Mark"

Использование функций-конструкторов.

function Person(name) {
   this.name = name;
}
Person.prototype.greeting = function () {
   return `Hi, I'm ${this.name}`;
}
const mark = new Person("Mark");
mark.greeting(); //returns "Hi, I'm Mark"

Использование метода Object.create.

const n = {
   greeting() {
      return `Hi, I'm ${this.name}`;
   }
};
const o = Object.create(n); // sets the prototype of "o" to be "n"
o.name = "Mark";
console.log(o.greeting()); // logs "Hi, I'm Mark"

62. В чем разница между методами Object.seal и Object.freeze?

Разница между этими двумя методами заключается в том, что когда мы применяем метод Object.freeze к объекту, свойства этого объекта неизменяемы, то есть мы не можем изменять или редактировать значения этих свойств. В то время как в методе Object.seal мы можем изменить эти существующие свойства, но мы не можем добавить новые свойства к объекту.

63. В чем разница между оператором in и методом hasOwnProperty в объектах?

Как вы знаете, обе эти функции проверяют, существует ли свойство в объекте. Он вернет truefalse. Разница между ними заключается в том, что оператор in также проверяет цепочку прототипов объектов, если свойство не было найдено в текущем объекте, в то время как метод hasOwnProperty просто проверяет, существует ли свойство в текущем объекте, игнорируя цепочка прототипов.

// We'll still use the object in the previous question.
console.log("prop" in o); // This logs true;
console.log("toString" in o); // This logs true, the toString method is available in this object's prototype which is the Object.prototype

console.log(o.hasOwnProperty("prop")); // This logs true
console.log(o.hasOwnProperty("toString")); // This logs false, does not check the object's prototype

64. Как можно работать с асинхронным кодом в JavaScript?

65. В чем разница между выражением функции и объявлением функции?

Допустим, у нас есть пример ниже.

hoistedFunc();
notHoistedFunc();
function hoistedFunc(){
  console.log("I am hoisted");
}
var notHoistedFunc = function(){
  console.log("I will not be hoisted!");
}

Вызов notHoistedFunc вызывает ошибку, а вызов hoistedFunc — нет, потому что hoistedFunc поднят, а notHoistedFunc — нет.
Читать Подъем здесь.

66. Сколько способов можно вызвать функцию?

Существует 4 способа вызвать функцию в JavaScript. Вызов определяет значение this или объект "владелец" этой функции.

  • Вызов как функция. Если функция вызывается не как метод, конструктор или с методами apply, call, она вызывается как функция. Объектом «владельца» этой функции будет объект window.
//Global Scope
  function add(a,b){
    console.log(this);
    return a + b;
  }  
  add(1,5); // logs the "window" object and returns 6
  const o = {
    method(callback){
      callback();
    }
  }
  o.method(function (){
      console.log(this); // logs the "window" object
  });
  • Вызов как метод. Если свойство объекта имеет значение функции, мы называем его методом. Когда этот метод вызывается, значением this этого метода будет этот объект.
const details = {
     name : "Marko",
     getName(){
       return this.name;
     }
   }
   details.getName(); // returns Marko
   // the "this" value inside "getName" method will be the "details" object
  • Вызов в качестве конструктора. Если функция была вызвана с ключевым словом new перед ней, то она называется function constructor. Будет создан пустой объект, и this будет указывать на этот объект.
function Employee(name, position, yearHired) {
  // creates an empty object {}
  // then assigns the empty object to the "this" keyword
  // this = {};
  this.name = name;
  this.position = position;
  this.yearHired = yearHired;
  // inherits from Employee.prototype
  // returns the "this" value implicitly if no 
  // explicit return statement is specified
};
const emp = new Employee("Marko Polo", "Software Developer", 2017);
  • Вызов с помощью методов apply и call. Если мы хотим явно указать значение this или объект-"владелец" функции, мы можем использовать эти методы. Эти методы доступны для всех функций.
const obj1 = {
 result:0
};
const obj2 = {
 result:0
};

function reduceAdd(){
   let result = 0;
   for(let i = 0, len = arguments.length; i < len; i++){
     result += arguments[i];
   }
   this.result = result;
}

reduceAdd.apply(obj1, [1, 2, 3, 4, 5]);  //the "this" object inside the "reduceAdd" function will be "obj1"
reduceAdd.call(obj2, 1, 2, 3, 4, 5); //the "this" object inside the "reduceAdd" function will be "obj2"

67. Что такое мемоизация и зачем она нужна?

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

68. Реализуйте вспомогательную функцию запоминания.

function memoize(fn) {
  const cache = {};
  return function (param) {
    if (cache[param]) {
      console.log('cached');
      return cache[param];
    } else {
      let result = fn(param);
      cache[param] = result;
      console.log(`not cached`);
      return result;
    }
  }
}
const toUpper = (str ="")=> str.toUpperCase();
const toUpperMemoized = memoize(toUpper);
toUpperMemoized("abcdef");
toUpperMemoized("abcdef");

Эта вспомогательная функция memoize работает только с функцией, которая принимает один аргумент. Нам нужно создать вспомогательную функцию memoize, которая принимает несколько аргументов.

const slice = Array.prototype.slice;
function memoize(fn) {
  const cache = {};
  return (...args) => {
    const params = slice.call(args);
    console.log(params);
    if (cache[params]) {
      console.log('cached');
      return cache[params];
    } else {
      let result = fn(...args);
      cache[params] = result;
      console.log(`not cached`);
      return result;
    }
  }
}
const makeFullName = (fName, lName) => `${fName} ${lName}`;
const reduceAdd = (numbers, startingValue = 0) => numbers.reduce((total, cur) => total + cur, startingValue);
const memoizedMakeFullName = memoize(makeFullName);
const memoizedReduceAdd = memoize(reduceAdd);
memoizedMakeFullName("Marko", "Polo");
memoizedMakeFullName("Marko", "Polo");
memoizedReduceAdd([1, 2, 3, 4, 5], 5);
memoizedReduceAdd([1, 2, 3, 4, 5], 5);

69. Почему typeof null возвращает object? Как проверить, является ли значение null?

typeof null == 'object' всегда будет возвращать true, потому что это была реализация null с момента рождения JavaScript. Было предложено исправить изменение typeof null == 'object' на typeof null == 'null', но оно было отклонено, так как это приведет к большему количеству ошибок.

Мы можем использовать оператор === или строгого равенства, чтобы проверить, является ли значение null.

function isNull(value){
    return value === null;
  }

70. Что делает ключевое слово new?

Ключевое слово new используется с функциями конструктора для создания объектов
в JavaScript.

Предположим, у нас есть пример кода ниже.

function Employee(name, position, yearHired) {
  this.name = name;
  this.position = position;
  this.yearHired = yearHired;
};
const emp = new Employee("Marko Polo", "Software Developer", 2017);

Ключевое слово new выполняет 4 функции.

  • Создает пустой объект.
  • Присваивает этому пустому объекту значение this.
  • Функция наследуется от functionName.prototype.
  • Возвращает this, если не используется явный оператор return.

На изображении выше он сначала создаст пустой объект {}, затем
присвоит этому пустому объекту this = {} значение this и добавит свойства этому объекту this. Поскольку у нас нет явного оператора return, он автоматически возвращает нам this.

Спасибо, ребята, что прочитали этот пост.

Хорошего дня 😃