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

1.Обещания

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

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

Промисы широко используются в библиотеках и фреймворках JavaScript, таких как AngularJS, ReactJS и Node.js. Представленные в ES6, они являются фундаментальной концепцией современной разработки JavaScript. Удобочитаемость, ремонтопригодность и производительность вашего кода можно значительно улучшить, зная, как правильно использовать промисы.

При использовании обещаний JavaScript объект «promise» представляет собой конструктор, который создает новое обещание и принимает единственный аргумент, который представляет собой функцию, называемую «исполнитель». Функция-исполнитель принимает два параметра: «resolve» и «reject», которые можно использовать для указания того, была ли асинхронная операция успешной или неудачной.

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

После создания промиса вы можете использовать его метод then для присоединения обратных вызовов, которые будут вызываться при разрешении промиса, и его метод catch для присоединения обратных вызовов. который будет вызываться, когда обещание будет отклонено. Кроме того, вы можете одновременно управлять несколькими промисами, используя методы Promise.all() и Promise.race(). Обещания доступны во всех современных средах JavaScript и поддерживаются всеми основными браузерами, поэтому вы можете уверенно использовать их в своих проектах.

2. Асинхронно/ожидание

Как и промисы, функция «async/await» используется в JavaScript для обработки асинхронных операций. Он был представлен в ECMAScript 2017 (ES8) и построен на основе обещаний сделать асинхронный код в JavaScript более управляемым и легким для чтения. Async/await предлагает метод создания асинхронного кода с синхронным внешним видом и поведением.

Асинхронная функция определяется ключевым словом «async». Затем асинхронная функция может выдать обещание и использовать ключевое слово «await», чтобы отложить выполнение кода, пока она ожидает выполнения обещания.

Пример показан ниже:

В приведенном выше коде «fetch» — это асинхронная функция, которая возвращает обещание, а ключевое слово «await» используется для ожидания разрешения обещания перед анализом данных JSON. .

Использование async/await делает ваш код более понятным, поддерживаемым и более надежным. И по сравнению с обратными вызовами и промисами это более современный, понятный и эффективный способ написания асинхронного кода.

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

3. Закрытие

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

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

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

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

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

4. Прототипное наследование

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

Каждый объект JavaScript имеет внутреннее свойство __proto__ (или [[Prototype]]), которое указывает на другой объект, известный как «объект-прототип». Когда осуществляется доступ к свойствам или методам объекта, JavaScript сначала определяет, имеет ли сам объект свойство или метод, определенные непосредственно для него. Если это не так, JavaScript проверяет объект-прототип объекта и продолжает поиск по цепочке прототипов, пока либо не найдет свойство или метод, либо не достигнет конца цепочки.

Давайте посмотрим на пример ниже:

Из кода выше видно, что объект «dog» в этом примере наследует атрибут «eats» от «animal», его прототипа. объекта, а не указывать его непосредственно на нем. Так работает прототипное наследование. Это механизм, в котором объекты могут наследовать свойства и методы других объектов.

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

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

5. Карри

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

В качестве примера рассмотрим функцию, которая принимает два аргумента x и y и возвращает их сумму.

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

На этом рисунке первоначальное использование add(2) дает новую функцию, которая принимает последний аргумент y. Поскольку значения x и y уже установлены на 2 и 3 соответственно, при вызове add2(3) результат равен 5.

Оператор спреда и стрелочные функции также могут использоваться для каррирования. Давайте посмотрим на пример ниже:

На этом рисунке первый вызов add(2) создает новую стрелочную функцию, которая добавляет x и y к любым оставшимся аргументам, независимо от их количества.

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

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

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

Некоторые примеры функций высшего порядка:

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

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

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

IV. Array.prototype.forEach(): эта функция является итеративным методом и вызывает предоставленную функцию обратного вызова один раз для каждого элемента в массиве в порядке возрастания индекса.

v. setTimeout(): эта функция принимает функцию обратного вызова в качестве входных данных и планирует ее выполнение на заданный период времени в будущем.

ви. Promise.then(): эта функция принимает функцию обратного вызова в качестве входных данных и планирует ее выполнение на момент разрешения обещания.

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

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

7. Генераторы

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

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

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

В приведенном выше примере ключевое слово function* используется для объявления функции-генератора fibonacci(). Он использует ключевое слово yield для возврата текущего значения a и обновляет значения a и b с помощью деструктурирующего присваивания. Цикл while гарантирует, что генератор будет продолжать создавать новые значения бесконечно.

Функция генератора при вызове возвращает объект итератора, который можно использовать для управления выполнением генератора. Метод next() используется для возобновления выполнения и возврата следующего значения.

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

8. WeakMaps и WeakSets

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

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

Вот пример использования WeakMap в JavaScript:

В приведенном выше примере мы создали WeakMap и сохранили пару ключ-значение с объектом, выступающим в качестве ключа. Затем мы используем объект в качестве ключа для получения значения. Пара ключ-значение также удаляется из WeakMap, когда мы присваиваем объекту значение null, что делает его пригодным для сборки мусора.

Однако пример WeakSet показан ниже:

В этом примере к созданному WeakSet добавляются два объекта. Затем используется метод has(), чтобы определить, присутствует ли определенный объект в наборе. Первый объект удаляется из WeakSet и подлежит сборке мусора после того, как мы установим для него значение null.

И WeakMap, и WeakSet полезны для управления использованием памяти JavaScript, поскольку они позволяют хранить информацию, не сохраняя ее в памяти постоянно.

9. Прокси

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

Следующий код является примером того, как прокси-сервер можно использовать для перехвата доступа к свойствам:

В этом примере объект с именем obj заключен в объект Proxy. Для обработки доступа к свойствам и их назначения мы определяем две функции «обработчика», «get» и «set». С помощью этих функций мы можем перехватить и изменить поведение базового объекта. Будет вызвана функция «get», сообщение будет зарегистрировано, и значение свойства «name» из исходного объекта будет возвращено при доступе к имени. свойство прокси-объекта.

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

  • Реализация пользовательских методов доступа к свойствам
  • Реализация вызова пользовательского метода
  • Реализация пользовательских конструкторов
  • Реализация пользовательского поведения для «виртуальных» объектов
  • Реализация пользовательского поведения для существующих объектов
  • Реализация пользовательской обработки ошибок
  • Внедрение пользовательских функций безопасности

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

10. Отражение API

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

Давайте посмотрим на пример ниже:

В этом примере свойству «имя» объекта obj присваивается значение «Джон» с помощью метода Reflect.set(). Когда операция завершается успешно, метод возвращает значение true.

Вот еще один пример того, как использовать Reflect API, чтобы определить, является ли объект расширяемым:

В этом примере показано, как проверить расширяемость объекта с помощью метода Reflect.isExtensible(). Из-за своего расширяемого характера по умолчанию он изначально возвращает true. После этого мы используем Object.preventExtensions(obj), чтобы остановить расширение объекта. Затем мы снова используем Reflect.isExtensible(obj), который возвращает false, чтобы указать, что объект больше не является расширяемым.

API Reflect предоставляет ряд методов, таких как:

  • Отразить.получить()
  • Reflect.set()
  • Reflect.has()
  • Reflect.deleteProperty()
  • Reflect.defineProperty()
  • Reflect.getOwnPropertyDescriptor()
  • Reflect.getPrototypeOf()
  • Reflect.setPrototypeOf()
  • Reflect.preventExtensions()
  • Reflect.isExtensible()
  • Отражение.применить()
  • Reflect.construct ()

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

В заключение, овладение JavaScript требует твердого понимания широкого спектра концепций и методов. Концепции, обсуждаемые в этой статье, такие как замыкания, прототипы, функции высшего порядка, — это лишь некоторые из многих, которые необходимы для понимания того, как работает JavaScript и как писать эффективный и действенный код. Кроме того, понимание того, как использовать современные функции, такие как Promises, async/await, WeakMap и WeakSet, Proxies и Reflect API, которые также обсуждаются здесь, может помочь вам писать более современный и мощный код JavaScript. Потратив время на то, чтобы полностью понять эти концепции и то, как они работают, вы сможете стать более опытным и уверенным в себе разработчиком JavaScript.