Первая из трех частей серии по основам JavaScript от SSENSE-TECH

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

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

В этой серии статей о JavaScript Essentials я объясню некоторые ключевые концепции, которые обычно неправильно понимаются или игнорируются. Часть 1 посвящена ключевому слову this .

ЧТО ТАКОЕ this

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

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

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

ПРИВЯЗКА ПО УМОЛЧАНИЮ

Вы можете думать об этом как о резервном механизме, когда нет явного указания того, что должно означать this.

Подумайте об этом правиле всякий раз, когда функция будет вызвана как отдельная функция; это означает, что это не метод объекта, и this не имеет принудительного значения. Для такого сценария this будет глобальным объектом, если не применяются ограничения при работе в strict mode. Есть много примеров, иллюстрирующих эту точку зрения, ярким примером является функция обратного вызова, переданная в качестве аргумента методу filter в массиве:

Этот код вызовет ошибку, и может быть трудно выяснить причину, почему среда выполнения попыталась найти метод isPair на объекте undefined? Во-первых, нам нужно знать, что функции являются первоклассными гражданами, что означает, что вы можете взаимодействовать с ними, как если бы они были любым другим объектом, что также означает, что вы можете передавать их в качестве аргументов другим функциям. Функции, передаваемые в качестве аргументов, известны как callbacks, и они всегда выполняются как автономные вызовы, что также означает, что применяется правило привязки по умолчанию и this будет привязан к глобальному объекту. Причина, по которой выдается последняя строка, заключается в том, что я запустил код в strict mode, а доступ к глобальному объекту ограничен.

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

Итак, как решить эту проблему?

Явная привязка

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

bind возвращает функцию, для которой this установлено значение объекта, переданного в качестве аргумента. Эта привязка является одним из возможных решений Array.filter проблемы, указанной в разделе привязка по умолчанию:

Разница между bind и call заключается в том, что bind не выполняет функцию, а создает функцию, которую вы можете выполнить позже, а call выполняет функцию сразу.

ПОДРАЗУМЕВАЕМЫЕ ПРИВЯЗКИ

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

new BINDING

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

В этом случае произойдет четыре шага:

  1. Пустой объект {} создается, как только функция-конструктор вызывается с оператором new.
  2. Этот пустой объект привязан к выполнению этой конкретной функции, поэтому любая ссылка на this внутри функции вступит в силу для этого объекта.
  3. Объект [[Prototype]] связан с функцией-конструктором.
  4. Возвращаемое значение выполнения функции - вновь созданный объект.

ФУНКЦИИ СО СТРЕЛКАМИ

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

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

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

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

Из-за этих функций этот тип функции не подходит для call, apply или bind .

У стрелочных функций есть другие функциональные и синтаксические отличия, например тот факт, что они не могут использоваться в качестве конструкторов, как обычные функции, и что у них нет свойства prototype, которое допускает prototype наследование. Объяснение всех остальных различий выходит за рамки данной статьи. Пожалуйста, обратитесь к разделу Дополнительные ресурсы и ссылки по теме, чтобы узнать больше.

ЗАКЛЮЧЕНИЕ

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

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

Следите за обновлениями второй части этой серии статей SSENSE-TECH JavaScript Essentials, в которой рассматривается асинхронное выполнение.

ДОПОЛНИТЕЛЬНЫЕ РЕСУРСЫ И СВЯЗАННЫЕ ССЫЛКИ

Редакционные обзоры Deanna Chow, Liela Touré и Pablo Martinez. Хотите работать с нами? Нажмите здесь, чтобы увидеть все открытые вакансии на SSENSE!