Для успешного развития и прохождения рабочего собеседования

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

Показатель

Основные концепции

  • Динамический
  • Ссылка VS Value
  • Оператор равенства (==) VS. Оператор идентификации (===)
  • Сфера
  • Подъем
  • Закрытие
  • МИЭФ
  • Обратные вызовы
  • Функции высшего порядка

ES6+

  • Распространение синтаксиса
  • Деструктуризация
  • Остаточный синтаксис
  • Классы
  • Обещания
  • Асинхронное ожидание
  • Стрелочные функции

Основные концепции

Динамический

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

Ссылка vs. значение

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

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

Подробнее о важности неизменяемости: Понимание неизменяемости в JavaScript.

По стоимости:

const value= 'Hello world!';
value[0] = 'P';
console.log(value); 
//Hello world, not Pello world!

По ссылке:

const car1 = {
  brand: 'Ford',
  model: 'Mustang W-Code'
}
const car2 = car1;
car2.model= 'Thunderbird';
console.log(car1 === car2); 
//true
console.log(car1);
//{brand: 'Ford', model: 'Thunderbird'}

Оператор равенства (==) VS. Оператор идентификации (===)

Основное различие между операторами «==» и «===» заключается в том, что «==» сравнивает переменную, выполняя приведение типа, а === сравнивает переменную, используя строгое равенство, и как тип, так и значение, которое мы сравниваем, должны быть идентичными. .

Пример

10 === 10
//true
10 == "10"
//true (Although 10 is a number and the "10" a string)

Сфера

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

Но где живут эти переменные? Где они хранятся? Как наша программа их получает? И наконец, что такое Scope?

«Область действия» - это область нашего кода, в которой действует идентификатор.

В JavaScript у нас есть четыре типа ScopeScope:

  • Global ScopeScope: виден всем (var)
  • Область действия функции: видна внутри функции (var)
  • Область действия блока (ES6 +): видна внутри блока (let, const)
  • Модуль (ES6 +): виден внутри модуля

Подъем

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

Пример:

a = 10; 
//Assign 10 to "a"
console.log(a);
//10
var a;
//Declare the "a" variable

Закрытие

Замыкание - это сочетание функции, объединенной вместе (заключенной) со ссылками на ее окружающее состояние, что дает вам доступ к Scope внешней функции из внутренней функции.

Пример:

function foo() {
  let myVar = 'Hello!!'; 
  //myVar is a local variable created by foo
  function alertMyVar() { 
    //alertMyVar() is the closure
    alert(name); 
    //Alert use the variable declared in the parent function
  }
  alertMyVar();
}
foo();

Функция foo () создает локальную переменную myVar и функцию alertMyVar (). Функция alertMyVar () - это внутренняя функция, которая определена внутри функции foo () и доступна только в теле функции foo (). alertMyVar () имеет доступ к переменным внешних функций, поэтому alertMyVar () может получить доступ к переменной myVar, объявленной в родительской функции.

IIFE

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

Пример:

(function() {
   let name= "Hello world!";
   alert(name);
  }
)();
//Hello world!

Таким образом, мы используем IIFE в основном из-за конфиденциальности. Любые переменные, объявленные внутри функции IIFE, недоступны из внешнего мира.

Обратный звонок

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

function runAsyncFunction(param1, callback) {
  //Do some stuff, 
  //for example download
  //data for a externan URL.
  //After a while...
  result = 100;
  callback(result);
}
runAsyncFunction(10, (r) => {...}));
//..
//Execute other tasks
//while the runAsyncFunction
//is running asynchronously.

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

Функции высшего порядка

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

Рассмотрим следующий пример:

const myArray = [1,2,3,4];
const myMultiplyFuncion = (n) => n*2;
newArray = myArray.map(myMultiplyFuncion);
console.log(newArray);
//[2, 4, 6, 8]

Высшей функцией здесь является .map () функция, которая принимает myMultiplyFuncion и возвращает новый массив со значениями, умноженными на два.

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

Хотя этот пример немного глуп, потому что вы можете использовать str.toUpperCase () напрямую, он служит для демонстрации того, как одна функция может возвращать другую:

const myToUpperCasse = function(str) {
  return str.toUpperCase();
};
console.log(myToUpperCasse("hello world!"));
//HELLO WORLD!

ES6+

Распространение синтаксиса

Мы используем оператор распространения «…», чтобы вытащить отдельные элементы из массива.

Синтаксис: someFunction (… iterableObj);

Рассмотрим следующий пример:

const myArray = [1,2,3,4,5,6,7,8];
const min = Math.min(...myArray);
console.log(min);
//1

Мы не можем применить Math.min напрямую с myArray, потому что он не принимает массив в качестве аргумента; он принимает отдельные элементы в качестве аргументов. Вместо этого мы можем сделать это, используя синтаксис распространения.

В следующем примере мы используем элементы массива в качестве аргументов функции:

function sum(a, b, c) {
  return a + b + c;
}
const numbers = [1, 2, 3];
console.log(sum(...numbers));
//6

Объединение массивов:

let myArray1 = [1, 2, 3];
let myArray2 = [4, 5, 6];
concatenatedArray = [...arr1, ...arr2];
console.log(concatenatedArray);
//[1,2,3,4,5,6]

Объединение предметов:

const myObj1= { name: "Rick" };
const myObj2= { age:40, year: 1980 };
const mergedObj = { ...myObj1, ...myObj2 };
console.log(mergedObj);
//{name: "Rick", age: 40, year: 1980}

Деструктуризация

Деструктуризация - это выражение JavaScript, которое позволяет извлекать свойства значений из объектов или массивов в отдельные переменные:

let var1, var2;
[var1, var2] = [1, 2];
console.log(var1);
//1
console.log(var2);
//2
...
const myConst= ['1', '2', '3'];
const [n1, n2, n3] = myConst;
console.log(n1); 
//"1"
console.log(n2);
//"2"
console.log(n3);
//"3"

Мы также можем легко поменять местами переменные:

let var1 = 1;
let var2 = 2;
[var1, var2] = [var2, var1];
console.log(var1); 
//3
console.log(var2); 
//1

Остаточный синтаксис

Остальной синтаксис позволяет нам представить несколько аргументов в виде массива.

Синтаксис: function f (a, b,… theArgs) {
// Делаем кое-что.
}

function sum(...theArgs) {
  return theArgs[0] + theArgs[5];
}
sum(1, 2, 3, 4, 5, 6);
//7

Только последний аргумент может быть «параметром отдыха»:

function sum(a, b, ...theArgs) {
  console.log(a);//1 
  console.log(b);//2
return theArgs[0] + theArgs[3];
}
sum(1, 2, 3, 4, 5, 6);
//a:1,b:2
//9 -> (theArgs[0]:3 + theArgs[3]:6)

Классы

Классы Javascript - это синтаксический сахар над существующими функциями наследования и конструктора на основе прототипов.

Используя шаблон конструктора:

function ConstructorCar (brand, model) {
    this.brand = brand;
    this.model = model;
}
ConstructorCar.prototype.isFord = function (brand) {   
   return this.brand === "Ford";
};
myCar = new ConstructorCar("Ford", "Sierra");
console.log(myCar.isFord("Ford"));
//true

Расширяет нашу функцию конструктора с помощью метода isBMW ():

ConstructorCar.prototype.isBMW = function (brand) {   
   return this.brand === "BMW";
};
myCarBWM = new ConstructorCar("BMW", "505");
console.log(myCarBWM.isBMW("BMW"));
//true

Эквивалент с использованием синтаксиса класса:

class Car {
  constructor(brand, model) {
    this.brand = brand;
    this.model = model;
  }
isFord(brand){
    return this.brand === "Ford";
  }
}
myCar = new Car("Ford", "Sierra");
console.log(myCar.isFord("Ford"));
//true

Расширьте класс с помощью метода isBmw ():

class CarBMW extends Car{
  constructor(brand, model) {
     super(brand,model);
  }
  isBMW(brand){
    return this.brand === brand;
 }
}
myCar1 = new CarBMW("Ford", "Sierra");
console.log(myCar1.isFord("Ford"));
//true
myCar2 = new CarBMW("BMW", "505");
console.log(myCar2.isBMW("BMW"));
//true

Обещания

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

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

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

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

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

Тот же пример, когда мы используем обратные вызовы с использованием обещаний, будет:

Асинхронное ожидание

Async / Await - это новое дополнение в ES2017, которое помогает нам писать полностью синхронный код для асинхронных задач.

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

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

Тот же пример обещаний, но с использованием Async / await:

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

Promises и Async / Await достигают того же, но Async / Await делает обработку асинхронного кода более естественной. Оба устраняют необходимость в обратных вызовах и знаменитом аду обратных вызовов.

Вы можете прочитать мою полную статью об асинхронном коде JavaScript в: Путешествие от обратных вызовов к асинхронному ожиданию в JavaScript.

Стрелочные функции

Стрелочная функция - это синтаксически компактная альтернатива обычной функции; В отличие от обычной функции, стрелочная функция не связывает объект «this». Вместо этого объект «this» привязан лексически, сохраняя свой исходный контекст.
Обратите внимание, что выражения функций со стрелками не подходят в качестве методов, и их нельзя использовать в качестве конструкторов или в рекурсивных функциях, но они очень полезны в таких функциях, как map (), reduce () или filter ()

const sum = function(a, b){
   return a + b;
}
Equivalent arrow function:
const sum = (a,b) => a+b;

С функцией фильтрации:

let array = [1,2,3,4,5]
let newArray = array.filter( e => e > 2);
//[3,5,5]

Заключение

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

Надеюсь, вам понравилась эта статья. Большое спасибо, что прочитали меня!

Заметка от Plain English

Вы знали, что у нас четыре публикации? Проявите немного любви, предложив им следующее: JavaScript на простом английском, AI на простом английском, UX на простом английском , Python на простом английском - спасибо и продолжайте учиться!

Кроме того, мы всегда заинтересованы в продвижении хорошего контента. Если у вас есть статья, которую вы хотели бы отправить в какую-либо из наших публикаций, отправьте электронное письмо по адресу [email protected] с вашим именем пользователя Medium и тем, о чем вы хотите написать, и мы вернуться к вам!