Довольно интересен рассказ о языке JavaScript. Для тех, кто не в курсе, ниже приведены некоторые основные моменты популярного многопарадигмального языка:
- Брендан Эйх (@BrendanEich), программист в Netscape Communications Corporation, создал Mocha всего за 10 дней в 1995 году.
- Вскоре Mocha будет называться JavaScript - который не имеет ничего общего с Java - и, вероятно, был маркетинговым подходом для увеличения популярности Java.
- JavaScript был представлен как возможность для обеспечения динамического программирования в то время, когда веб-сайты были в основном статичными.
- С 1996 года Спецификация языка ECMAScript (ECMA-262) определила и стандартизировала язык JavaScript, теперь в 11-м издании.
- JavaScript работает примерно в 97% всех браузеров по всему миру.
- JavaScript стал основным выбором для таких клиентских фреймов, как Angular, React и Vue.js, а также для среды выполнения Node.js.
С тех пор, как JavaScript стал мейнстримом, я участвовал в проектах, в которых так или иначе использовался JavaScript. В те первые дни HTML-файлы ссылались на JavaScript для выполнения простой проверки перед отправкой запросов во внутреннюю службу. Теперь каждый веб-проект, над которым я работал за последние 7 лет, использует клиентскую структуру, полностью построенную на JavaScript.
Тем не менее, JavaScript не свободен от проблем дизайна, которые я отмечал в своей публикации Пройдет ли JavaScript испытание временем? Еще в июне 2017 года.
Один из пунктов, не упомянутых тогда, - это обсуждение того, когда использовать класс, а когда использовать прототип в JavaScript. Моя цель этой статьи - сосредоточиться на этих концепциях - даже при использовании существующей инфраструктуры, такой как Веб-компоненты Salesforce Lightning (LWC).
Концепция прототипа в JavaScript
Для целей этой статьи лучше всего сначала поговорить о концепции прототипа в JavaScript.
В JavaScript все объекты наследуют свойства и методы от прототипа. Рассмотрим следующий пример прототипа:
function Vehicle(vinNumber, manufacturer, productionDate, fuelType) { this.manufacturer = manufacturer; this.vinNumber = vinNumber; this.productionDate = productionDate; this.fuelType = fuelType; } Vehicle.prototype.vehicleInformation = function() { var productionDate = new Date(this.productionDate * 1000); var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; var year = productionDate.getFullYear(); var month = months[productionDate.getMonth()]; var day = productionDate.getDate(); var friendlyDate = month + ' ' + day + ', ' + year; return this.manufacturer + ' vehicle with VIN Number = ' + this.vinNumber + ' was produced on ' + friendlyDate + ' using a fuel type of ' + this.fuelType; }
В результате этого кода доступен объект Vehicle
, и новый экземпляр может быть создан с помощью следующего кода:
let rogue = new Vehicle('5N1FD4YXN11111111', 'Nissan', 1389675600, 'gasoline');
Имея эту информацию, функция vehicleInformation()
может быть вызвана, используя следующий подход:
alert(rogue.vehicleInformation());
Это вызовет диалоговое окно с предупреждением, содержащее это сообщение:
«Автомобиль Nissan с VIN-номером 5N1FD4YXN11111111 был произведен 14 января 2014 г. с использованием бензина»
Как и следовало ожидать, второй прототип под названием SportUtilityVehicle
может быть представлен для дальнейшего определения данного типа транспортного средства:
function SportUtilityVehicle(vinNumber, manufacturer, productionDate, fuelType, drivetrain) { Vehicle.call(this, vinNumber, manufacturer, productionDate, fuelType); this.drivetrain = drivetrain; }
Теперь мы можем создать SportUtilityVehicle
вместо простого Vehicle
.
let rogue = new SportUtilityVehicle('5N1FD4YXN11111111', 'Nissan', 1389675600, 'gasoline', 'AWD');
Мы также можем определить новую версию с прототипом SportUtilityVehicle
:
SportUtilityVehicle.prototype.vehicleInformation = function() { return this.manufacturer + ' vehicle with VIN Number = ' + this.vinNumber + ' utilizes drivetrain = ' + this.drivetrain + ' and runs on ' + this.fuelType; }
Теперь, когда функция vehicleInformation()
вызывается с использованием следующего подхода:
alert(rogue.vehicleInformation());
Появится диалоговое окно с предупреждением, содержащее следующее сообщение:
«Автомобиль Nissan с номером VIN = 5N1FD4YXN11111111 использует трансмиссию = AWS и работает на бензине»
Класс JavaScript
Начиная с ECMAScript 2015 (выпущенного в 6-м издании в июне 2015 г.) в JavaScript появилась концепция класса. Хотя это может вызвать интерес у разработчиков, использующих такие языки, как Java, C # и C ++, цель введения опции класса заключалась в том, чтобы позволить создавать классы с использованием более простого и понятного синтаксиса. Фактически, в документации говорится, что классы - это просто «синтаксический сахар», упрощающий работу разработчика.
Преобразование предыдущего примера из прототипов в классы будет выглядеть, как показано ниже:
class Vehicle { constructor(vinNumber, manufacturer, productionDate, fuelType) { this.manufacturer = manufacturer; this.vinNumber = vinNumber; this.productionDate = productionDate; this.fuelType = fuelType; } vehicleInformation() { var productionDate = new Date(this.productionDate * 1000); var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']; var year = productionDate.getFullYear(); var month = months[productionDate.getMonth()]; var day = productionDate.getDate(); var friendlyDate = month + ' ' + day + ', ' + year; return this.manufacturer + ' vehicle with VIN Number = ' + this.vinNumber + ' was produced on ' + friendlyDate + ' using a fuel type of ' + this.fuelType; } } class SportUtilityVehicle extends Vehicle { constructor(vinNumber, manufacturer, productionDate, fuelType, drivetrain) { super(vinNumber, manufacturer, productionDate, fuelType); this.drivetrain = drivetrain; } vehicleInformation() { return this.manufacturer + ' vehicle with VIN Number = ' + this.vinNumber + ' utilizes drivetrain = ' + this.drivetrain + ' and runs on ' + this.fuelType; } }
Если нам нужно добавить геттеры и сеттеры в класс SportUtilityVehicle
, класс можно обновить, как показано ниже:
class SportUtilityVehicle extends Vehicle { constructor(vinNumber, manufacturer, productionDate, fuelType, drivetrain) { super(vinNumber, manufacturer, productionDate, fuelType); this.drivetrain = drivetrain; } vehicleInformation() { return this.manufacturer + ' vehicle with VIN Number = ' + this.vinNumber + ' utilizes drivetrain = ' + this.drivetrain + ' and runs on ' + this.fuelType; } get drivetrain() { return this._drivetrain; } set drivetrain(newDrivetrain) { this._drivetrain = newDrivetrain; } }
Как видите, синтаксис напоминает такие языки, как Java или C #. Классовый подход также позволяет функциям и атрибутам, принадлежащим цепочке прототипов, не ссылаться на синтаксис Object.prototype. Единственное требование - конструктор всегда назывался «конструктором».
JavaScript Класс v Прототип
Как отмечалось выше, класс в JavaScript - это просто синтаксический сахар, упрощающий работу разработчиков функций, работающих с JavaScript. Хотя этот подход допускает более общий дизайн для тех, кто исходит из таких языков, как Java, C # или C ++, многие пуристы Javascript вообще не советуют использовать классы.
На самом деле, одна проблема упоминается Михаилом Красновым в статье Пожалуйста, прекратите использовать классы в JavaScript:
Проблемы с привязкой. Поскольку функции конструктора класса тесно связаны с этим ключевым словом, оно может вызвать потенциальные проблемы с привязкой, особенно если вы попытаетесь передать свой метод класса в качестве обратного вызова внешней подпрограмме.
Майкл приводит еще четыре причины, по которым следует избегать использования классов Javascript, но сторонники варианта класса быстро уменьшили вес его мыслей.
Начиная с 2021 года, я придерживаюсь следующего заявления о миссии любого ИТ-специалиста:
«Сосредоточьте свое время на предоставлении функций / функций, которые увеличивают ценность вашей интеллектуальной собственности. Используйте фреймворки, продукты и услуги для всего остального ».
Когда дело доходит до использования класса или прототипа в JavaScript, я чувствую, что это решение должно быть принято командой, поддерживающей и поддерживающей базу кода. Если их уровень комфорта не имеет проблем после подхода прототипа, им следует соответствующим образом спроектировать свои компоненты. Однако, если предпочтение отдается использованию концепции класса, разработчики в этой команде должны понимать проблему связывания, указанную выше, но должны двигаться вперед и оставаться в пределах своей зоны комфорта.
Влияние на веб-компоненты Lightning
Несколько лет назад компания Salesforce представила веб-компоненты Lightning (LWC), о которых я рассказывал в статье Модель программирования Salesforce, предлагающая JavaScript. Почти три года спустя я начинаю говорить о влиянии использования классов и прототипов на разработчиков Salesforce.
Быстрый ответ ... это не имеет значения. Salesforce позволяет веб-компонентам Lightning использовать прототип или класс. Типичная модель наследования в JavaScript - через прототип. Но чтобы обратиться к разработчикам, которые привыкли к классическому наследованию, есть этот синтаксический сахар, который поможет разработчикам реализовать прототипное наследование с помощью подхода, который очень похож на классическое наследование.
Итак, когда дело доходит до LWC - а это все о наследовании, поскольку LWC построил замечательный компонент базового класса, который вы можете расширить, - вы также можете воспользоваться этим синтаксическим сахаром.
Вам не нужно беспокоиться о прототипном наследовании, даже если все это происходит под капотом. Просто сделайте классическое наследование, и вы будете золотыми.
Вот пример того, как это может выглядеть:
import { LightningElement } from 'lwc'; export default class VehicleComponent extends LightningElement { // properties go here vehicleInformation() { return this.manufacturer + ' vehicle with VIN Number = ' + this.vinNumber + ' utilizes drivetrain = ' + this.drivetrain + ' and runs on ' + this.fuelType; } }
Видеть? LWC - зная, что JavaScript дает вам этот синтаксический сахар - упрощает вам задачу.
Заключение
Я признаю, что JavaScript - это не тот язык, на разработку которого я тратил большую часть времени. Помимо разработки клиентов на Angular и небольших усилий с использованием Node.js, моя основная работа в качестве разработчика сервисов часто фокусируется на других языковых вариантах.
В то же время использование подхода классов вместо подхода прототипов обеспечивает аналогичный мост для разработчиков Java, C # и C ++. Хотя здесь нет правильного ответа, важно понимать, как и класс, и прототип работают в JavaScript.
В конце концов, наша роль заключается в том, чтобы иметь возможность поддерживать вашу базу кода, устранять дефекты и быстро возвращать функции и возможности. Реализованный подход всегда должен определяться исключительно пониманием и способностью специализированной группы поддерживать выбранные стандарты.
Хорошего дня!