JavaScript - JavaScript

JavaScript
Парадигма событийно-ориентированный , функциональный , императивный
Разработано Брендан Эйх из Netscape изначально; другие также внесли свой вклад в стандарт ECMAScript
Впервые появился 4 декабря 1995 г . ; 25 лет назад (1995-12-04)
Стабильный выпуск
ECMAScript 2021  Edit this on Wikidata / июнь 2021 ; 4 месяца назад (June 2021)
Предварительный выпуск
ECMAScript 2022/22  Edit this on Wikidata июля 2021 г . ; 2 месяца назад (22 July 2021)
Печатная дисциплина Динамичный , слабый , утка
Расширения имени файла
  • .js
  • .cjs
  • .mjs
Веб-сайт www .ecma-international .org / публикации и стандарты / стандарты / ecma-262 /
Основные реализации
V8 , JavaScriptCore , SpiderMonkey , Чакра
Под влиянием
Java , схема , AWK , HyperTalk
Под влиянием
TypeScript , CoffeeScript , AssemblyScript , ActionScript , Dart , Objective-J , Opa , Haxe

JavaScript ( / ɑː v ə ˌ ы к т ɪ р т / ), часто сокращенно JS , является языком программирования , который соответствует ECMAScript спецификации. JavaScript - это высокоуровневый , часто скомпилированный точно в срок и мультипарадигмальный . Он имеет синтаксис фигурных скобок , динамическую типизацию , объектную ориентацию на основе прототипов и функции первого класса .

Наряду с HTML и CSS , JavaScript является одной из основных технологий всемирной паутины . Более 97% веб-сайтов используют его на стороне клиента для поведения веб-страниц , часто с использованием сторонних библиотек . Большинство веб-браузеров имеют специальный механизм JavaScript для выполнения кода на устройстве пользователя .

Как язык с множеством парадигм, JavaScript поддерживает управляемые событиями , функциональные и императивные стили программирования . Он имеет интерфейсы прикладного программирования (API) для работы с текстом, датами, регулярными выражениями , стандартными структурами данных и объектной моделью документа (DOM).

Стандарт ECMAScript не включает в себя какие-либо средства ввода / вывода (I / O), такие как сети , хранилище или графические объекты. На практике веб-браузер или другая среда выполнения предоставляет API-интерфейсы JavaScript для ввода-вывода.

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

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

История

Создание в Netscape

Мозаика веб - браузер был выпущен в 1993 году первого браузера с графическим пользовательским интерфейсом , доступным для нетехнических людей, он играл важную роль в быстром росте зарождающейся World Wide Web . Затем ведущие разработчики Mosaic основали корпорацию Netscape , которая в 1994 году выпустила более совершенный браузер Netscape Navigator . Navigator быстро стал самым популярным браузером.

В те годы становления Интернета веб-страницы могли быть только статичными, не имея возможности динамического поведения после загрузки страницы в браузере. В быстро растущей среде веб-разработки было желание снять это ограничение, поэтому в 1995 году Netscape решила добавить язык сценариев в Navigator. Для этого они выбрали два пути: сотрудничество с Sun Microsystems для внедрения языка программирования Java , а также с привлечением Брендана Эйха для встраивания языка Scheme .

Руководство Netscape вскоре решило, что для Эйха лучше всего было разработать новый язык с синтаксисом, похожим на Java, но менее похожим на Scheme или другие существующие языки сценариев. Хотя новый язык и его реализация интерпретатора назывались LiveScript, когда впервые были представлены как часть бета-версии Navigator в сентябре 1995 года, название было изменено на JavaScript для официального выпуска в декабре. Эйх утверждает, что синтаксис HyperTalk и имена обработчиков повлияли на JavaScript.

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

Принятие Microsoft

Microsoft дебютировала Internet Explorer в 1995 году, что привело к войне браузеров с Netscape. На передней панели JavaScript, Microsoft обратной инженерии Навигатор интерпретатор , чтобы создать свой собственный, называемый JScript .

JScript был впервые выпущен в 1996 году вместе с первоначальной поддержкой CSS и расширений HTML . Каждая из этих реализаций заметно отличалась от своих аналогов в Navigator. Эти различия затрудняли разработчикам работу своих веб-сайтов в обоих браузерах, что привело к повсеместному использованию логотипов «лучше всего просматривается в Netscape» и «лучше всего просматривается в Internet Explorer» в течение нескольких лет.

Расцвет JScript

В ноябре 1996 года Netscape представила в Ecma International JavaScript в качестве отправной точки для стандартной спецификации, которой могли бы соответствовать все поставщики браузеров. Это привело к официальному выпуску первой спецификации языка ECMAScript в июне 1997 года.

Процесс стандартизации продолжался несколько лет, с выпуском ECMAScript 2 в июне 1998 года и ECMAScript 3 в декабре 1999 года. Работа над ECMAScript 4 началась в 2000 году.

Тем временем Microsoft завоевывала все более доминирующее положение на рынке браузеров. К началу 2000-х годов доля рынка Internet Explorer достигла 95%. Это означало, что JScript стал де-факто стандартом для клиентских сценариев в Интернете.

Первоначально Microsoft участвовала в процессе стандартизации и реализовала некоторые предложения на своем языке JScript, но в конце концов прекратила сотрудничество в работе над Ecma. Таким образом, ECMAScript 4 был законсервирован.

Рост и стандартизация

В период доминирования Internet Explorer в начале 2000-х клиентские сценарии находились в застое. Ситуация начала меняться в 2004 году, когда преемница Netscape, Mozilla , выпустила браузер Firefox . Firefox был хорошо принят многими, заняв значительную долю рынка у Internet Explorer.

В 2005 году Mozilla присоединилась к ECMA International, и началась работа над стандартом ECMAScript for XML (E4X). Это привело к тому, что Mozilla работала совместно с Macromedia (позже приобретенным Adobe Systems ), которые внедряли E4X в свой язык ActionScript 3, основанный на черновике ECMAScript 4. Целью стала стандартизация ActionScript 3 как нового ECMAScript 4. С этой целью Adobe Systems выпустила реализацию Tamarin как проект с открытым исходным кодом . Однако Tamarin и ActionScript 3 слишком отличались от общепринятых клиентских сценариев, и без сотрудничества с Microsoft ECMAScript 4 так и не реализовался.

Между тем, в сообществах разработчиков ПО с открытым исходным кодом, не связанных с работой ECMA, происходили очень важные события. В 2005 году Джесси Джеймс Гарретт выпустил официальный документ, в котором он ввел термин Ajax и описал набор технологий, из которых JavaScript был основой, для создания веб-приложений, в которых данные могут загружаться в фоновом режиме, избегая необходимости полной страницы. перезагружает. Это вызвало период возрождения JavaScript, во главе которого стояли библиотеки с открытым исходным кодом и сообщества, которые формировались вокруг них. Было создано много новых библиотек, включая jQuery , Prototype , Dojo Toolkit и MooTools .

Google дебютировал со своим браузером Chrome в 2008 году с движком V8 JavaScript, который был быстрее, чем его конкуренты. Ключевым нововведением была своевременная компиляция (JIT), поэтому другим поставщикам браузеров пришлось пересмотреть свои движки для JIT.

В июле 2008 года эти разрозненные партии собрались на конференцию в Осло . Это привело к окончательному соглашению в начале 2009 года, чтобы объединить всю соответствующую работу и продвинуть язык вперед. Результатом стал стандарт ECMAScript 5, выпущенный в декабре 2009 года.

Серверный JavaScript и Node.js

В 2009 году Райан Даль выпустил первую версию Node.js , которая объединила движок Google V8, цикл событий и низкоуровневый API ввода-вывода, чтобы обеспечить полную серверную среду программирования JavaScript, управляемую событиями. Это упростило обмен данными между клиентским и серверным кодом, позволяя веб-разработчикам, имеющим опыт работы с клиентским JavaScript, передавать свои навыки разработке на стороне сервера. В конечном итоге это привело к созданию сообщества из нескольких миллионов разработчиков, а также к npm , крупнейшему реестру программных пакетов в мире.

Достижение зрелости

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

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

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

Торговая марка

«JavaScript» является торговой маркой в корпорации Oracle в Соединенных Штатах.

Использование веб-сайта на стороне клиента

JavaScript является доминирующим языком сценариев на стороне клиента в Интернете, и 97% веб-сайтов используют его для этой цели. Сценарии встроены в HTML- документы или включены из них и взаимодействуют с DOM . Большинство веб-браузеров, включая подавляющее большинство браузеров Android и всех iPad, имеют встроенный механизм JavaScript, который выполняет код на устройстве пользователя.

Примеры поведения по сценарию

Библиотеки и фреймворки

Более 80% веб-сайтов используют стороннюю библиотеку JavaScript или веб-фреймворк для своих клиентских сценариев.

jQuery на сегодняшний день является самой популярной библиотекой, которую используют более 75% веб-сайтов. Facebook создал библиотеку React для своего веб-сайта, а затем выпустил ее с открытым исходным кодом ; другие сайты, включая Twitter , теперь используют его. Точно так же фреймворк Angular, созданный Google для своих веб-сайтов, включая YouTube и Gmail , теперь является проектом с открытым исходным кодом, используемым другими.

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

Другое использование

Использование JavaScript вышло за пределы своего веб-браузера . Механизмы JavaScript теперь встроены во множество других программных систем, как для развертывания веб - сайтов на стороне сервера, так и для приложений, не связанных с браузером .

Первоначальные попытки продвижения на стороне сервера использование JavaScript были Netscape Enterprise Server и Microsoft «s Internet Information Services , но они были небольшие ниши. Использование на стороне сервера в конце концов начало расти в конце 2000-х, с созданием Node.js и других подходов .

Electron , Cordova , React Native и другие фреймворки приложений использовались для создания многих приложений с поведением, реализованным на JavaScript. Другие небраузерные приложения включают поддержку Adobe Acrobat для создания сценариев PDF- документов и расширения GNOME Shell, написанные на JavaScript.

JavaScript недавно начал появляться в некоторых встроенных системах , обычно за счет использования Node.js.

Функции

Следующие функции являются общими для всех соответствующих реализаций ECMAScript, если явно не указано иное.

Императивный и структурированный

JavaScript поддерживает большую часть синтаксиса структурированного программирования из C (например, ifоператоры, whileциклы, switchоператоры, do whileциклы и т. Д.). Одним исключением является обзорным : первоначально JavaScript было только функция области видимости с var; затем область видимости блока была добавлена ​​в ECMAScript 2015 с ключевыми словами letи const. Как и C, JavaScript делает различие между выражениями и операторами . Одним из синтаксических отличий от C является автоматическая вставка точки с запятой , которая позволяет опускать точки с запятой (которые завершают операторы).

Слабо типизированный

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

  • Бинарный +оператор преобразует оба операнда в строку, если оба операнда не являются числами. Это потому, что оператор сложения дублирует оператор конкатенации.
  • Бинарный -оператор всегда приводит оба операнда к числу
  • Оба унарных оператора ( +, -) всегда приводят операнд к числу.

Значения преобразуются в следующие строки:

  • Строки оставлены как есть
  • Числа преобразуются в их строковое представление
  • Элементы массивов приводятся к строкам, после чего они соединяются запятыми ( ,)
  • Остальные объекты преобразуются в строку, [object Object]где Object- имя конструктора объекта.

Значения преобразуются в числа путем преобразования в строки, а затем преобразования строк в числа. Эти процессы можно изменить, определив toStringи valueOfфункции в прототипе для преобразования строк и чисел соответственно.

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

Преобразование типов JavaScript
левый операнд оператор правый операнд результат
[] (пустой массив) + [] (пустой массив) "" (пустой строки)
[] (пустой массив) + {} (пустой объект) "[object Object]" (нить)
false (логическое) + [] (пустой массив) "false" (нить)
"123"(нить) + 1 (количество) "1231" (нить)
"123" (нить) - 1 (количество) 122 (количество)

Часто также упоминается, что {} + []приводит к 0(число). Это вводит в заблуждение: {}интерпретируется как пустой блок кода вместо пустого объекта, и пустой массив преобразуется в число оставшимся унарным +оператором. Если вы заключите выражение в круглые скобки, ({} + [])фигурные скобки интерпретируются как пустой объект, и результат выражения будет таким, "[object Object]"как ожидалось.

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

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

Объектная ориентация (на основе прототипов)

Прототипное наследование в JavaScript описывается Дугласом Крокфордом как:

Вы создаете объекты-прототипы, а затем ... создаете новые экземпляры. Объекты изменяемы в JavaScript, поэтому мы можем дополнять новые экземпляры, давая им новые поля и методы. Затем они могут выступать в качестве прототипов даже для более новых объектов. Нам не нужны классы, чтобы создавать множество похожих объектов… Объекты наследуются от объектов. Что может быть более объектно-ориентированным, чем это?

В JavaScript объект - это ассоциативный массив , дополненный прототипом (см. Ниже); каждый ключ предоставляет имя для свойства объекта , и есть два синтаксических способа указать такое имя: точечная нотация ( obj.x = 10) и скобочная нотация ( obj['x'] = 10). Свойство может быть добавлено, восстановлено или удалено во время выполнения. Большинство свойств объекта (и любое свойство, которое принадлежит цепочке наследования прототипа объекта) можно перечислить с помощью for...inцикла.

Прототипы
JavaScript использует прототипы, тогда как многие другие объектно-ориентированные языки используют классы для наследования . Можно смоделировать многие функции на основе классов с помощью прототипов в JavaScript.
Функции как конструкторы объектов
Функции также являются конструкторами объектов, как и их типичная роль. Добавление к вызову функции префикса new создаст экземпляр прототипа, унаследовав свойства и методы от конструктора (включая свойства из Objectпрототипа). ECMAScript 5 предлагает Object.createметод, позволяющий явное создание экземпляра без автоматического наследования от Objectпрототипа (более старые среды могут назначать прототип null). Свойство конструктора prototypeопределяет объект, используемый для внутреннего прототипа нового объекта. Новые методы могут быть добавлены путем изменения прототипа функции, используемой в качестве конструктора. Встроенные конструкторы JavaScript, такие как Arrayили Object, также имеют прототипы, которые можно изменять. Хотя можно изменить Objectпрототип, это обычно считается плохой практикой, потому что большинство объектов в JavaScript наследуют методы и свойства от Objectпрототипа, и они могут не ожидать изменения прототипа.
Функции как методы
В отличие от многих объектно-ориентированных языков, нет различия между определением функции и определением метода . Скорее, различие происходит во время вызова функции; когда функция вызывается как метод объекта, локальное ключевое слово this функции привязано к этому объекту для этого вызова.

Функциональный

Функция является первым классом ; функция считается объектом. Таким образом, функция может иметь свойства и методы, такие как .call()и .bind(). Вложенная функция является функцией , определенной в пределах другой функции. Он создается каждый раз при вызове внешней функции. Кроме того, каждая вложенная функция образует лексическое замыкание : лексическая область видимости внешней функции (включая любую константу, локальную переменную или значение аргумента) становится частью внутреннего состояния каждого внутреннего объекта функции, даже после завершения выполнения внешней функции. . JavaScript также поддерживает анонимные функции .

Делегат

JavaScript поддерживает неявное и явное делегирование .

Функции как роли (черты и примеси)
JavaScript изначально поддерживает различные функциональные реализации шаблонов ролей , таких как Traits и Mixins . Такая функция определяет дополнительное поведение по крайней мере одним методом, привязанным к thisключевому слову в ее functionтеле. Затем роль должна быть явно делегирована через callили applyна объекты, которые должны иметь дополнительное поведение, которое не передается через цепочку прототипов.
Состав и наследование объектов
В то время как явное делегирование на основе функций охватывает композицию в JavaScript, неявное делегирование уже происходит каждый раз при обходе цепочки прототипов, например, для поиска метода, который может быть связан с объектом, но не принадлежит ему напрямую. Как только метод найден, он вызывается в контексте этого объекта. Таким образом, наследование в JavaScript покрывается автоматизмом делегирования, который привязан к свойству прототипа функций конструктора.

Разное

JS - это язык с нулевым индексом .

Среда выполнения
JavaScript обычно полагается на среду выполнения (например, веб-браузер ) для предоставления объектов и методов, с помощью которых сценарии могут взаимодействовать со средой (например, DOM веб-страницы ). Эти среды однопоточные . JavaScript также полагается на среду выполнения, чтобы обеспечить возможность включать / импортировать сценарии (например, элементы HTML <script> ). Это не языковая функция как таковая, но она распространена в большинстве реализаций JavaScript. JavaScript обрабатывает сообщения из очереди по одному. JavaScript вызывает функцию, связанную с каждым новым сообщением, создавая фрейм стека вызовов с аргументами функции и локальными переменными . Стек вызовов сжимается и увеличивается в зависимости от потребностей функции. Когда стек вызовов пуст после завершения функции, JavaScript переходит к следующему сообщению в очереди. Это называется циклом событий , описываемым как «выполнение до завершения», потому что каждое сообщение полностью обрабатывается до того, как будет рассмотрено следующее сообщение. Однако языковая модель параллелизма описывает цикл событий как неблокирующий : ввод / вывод программы выполняется с использованием событий и функций обратного вызова . Это означает, например, что JavaScript может обрабатывать щелчок мышью, ожидая, пока запрос к базе данных вернет информацию.
Вариадические функции
В функцию можно передать неопределенное количество параметров. Функция может получить к ним доступ через формальные параметры, а также через локальный argumentsобъект. Функции с переменным числом аргументов также можно создавать с помощью bindметода.
Литералы массивов и объектов
Как и многие языки сценариев, массивы и объекты ( ассоциативные массивы на других языках) могут быть созданы с помощью краткого синтаксиса сокращений. Фактически, эти литералы составляют основу формата данных JSON .
Регулярные выражения
JavaScript также поддерживает регулярные выражения аналогично Perl , которые обеспечивают сжатый и мощный синтаксис для обработки текста, более сложный, чем встроенные строковые функции.
Обещания
JavaScript также поддерживает обещания , которые представляют собой способ обработки асинхронных операций. Существует встроенный объект Promise, который предоставляет доступ ко многим функциям для обработки обещаний и определяет, как они должны обрабатываться. Это позволяет связать обработчики с конечным значением успеха или причиной сбоя асинхронного действия. Это позволяет асинхронным методам возвращать значения, как синхронные методы: вместо того, чтобы немедленно возвращать окончательное значение, асинхронный метод возвращает обещание предоставить значение в какой-то момент в будущем. Недавно в спецификацию JavaScript были введены методы комбинатора, которые позволяют разработчикам комбинировать несколько обещаний JavaScript и выполнять операции на основе различных сценариев. Представленные методы: Promise.race, Promise.all, Promise.allSettled и Promise.any.

Расширения для конкретных поставщиков

Исторически некоторые движки JavaScript поддерживали эти нестандартные функции:

  • условные catchпредложения (например, Java)
  • понимание массивов и выражения генератора (например, Python)
  • краткие функциональные выражения ( function(args) expr; этот экспериментальный синтаксис предшествовал стрелочным функциям)
  • ECMAScript for XML (E4X), расширение, которое добавляет встроенную поддержку XML в ECMAScript (не поддерживается в Firefox с версии 21)

Синтаксис

Простые примеры

Переменные в JavaScript могут быть определены с использованием как var, letили constключевые слова.

// Declares a function-scoped variable named `x`, and implicitly assigns the
// special value `undefined` to it. Variables without value are automatically
// set to undefined.
var x;

// Variables can be manually set to `undefined` like so
var x2 = undefined;

// Declares a block-scoped variable named `y`, and implicitly sets it to
// `undefined`. The `let` keyword was introduced in ECMAScript 2015.
let y;

// Declares a block-scoped, un-reassignable variable named `z`, and sets it to
// a string literal. The `const` keyword was also introduced in ECMAScript 2015,
// and must be explicitly assigned to.

// The keyword `const` means constant, hence the variable cannot be reassigned
// as the value is `constant`.
const z = "this value cannot be reassigned!";

// Declares a variable named `myNumber`, and assigns a number literal (the value
// `2`) to it.
let myNumber = 2;

// Reassigns `myNumber`, setting it to a string literal (the value `"foo"`).
// JavaScript is a dynamically-typed language, so this is legal.
myNumber = "foo";

Обратите внимание на комментарии в приведенном выше примере, которым предшествовали две косые черты .

В JavaScript нет встроенных функций ввода / вывода ; среда выполнения обеспечивает это. Спецификация ECMAScript в редакции 5.1 упоминает:

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

Однако в большинстве сред выполнения есть consoleобъект, который можно использовать для вывода на печать. Вот минималистичная программа Hello World на JavaScript:

console.log("Hello World!");

Простая рекурсивная функция:

function factorial(n) {
    if (n === 0)
        return 1; // 0! = 1

    return n * factorial(n - 1);
}

factorial(3); // returns 6

Функция анонимного (или лямбда):

function counter() {
    let count = 0;

    return function() {
        return ++count;
    };
}

let closure = counter();
closure(); // returns 1
closure(); // returns 2
closure(); // returns 3

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

Стрелочные функции были впервые представлены в 6-м издании - ECMAScript 2015 . Они сокращают синтаксис для написания функций на JavaScript. Стрелочные функции анонимны по своей природе; переменная необходима для ссылки на них, чтобы вызывать их после их создания.

Пример стрелочной функции:

// Arrow functions let us omit the `function` keyword.
// Here `long_example` points to an anonymous function value.
const long_example = (input1, input2) => {
    console.log("Hello, World!");
    const output = input1 + input2;

    return output;
};

// If there are no braces, the arrow function simply returns the expression
// So here it's (input1 + input2)
const short_example = (input1, input2) => input1 + input2;

long_example(2, 3); // Prints "Hello, World!" and returns 5
short_example(2, 5);  // Returns 7

// If an arrow function only has one parameter, the parentheses can be removed.
const no_parentheses = input => input + 2;

no_parentheses(3); // Returns 5

В JavaScript объекты создаются так же, как и функции; это называется функциональным объектом .

Пример объекта:

function Ball(r) {
    this.radius = r; // the "r" argument is local to the ball object
    this.area = Math.PI * (r ** 2); // parentheses don't do anything but clarify
    
    // objects can contain functions ("method")
    this.show = function() {
        drawCircle(this.radius); // references another function (that draws a circle)
    };
}

let myBall = new Ball(5); // creates a new instance of the ball object with radius 5
myBall.radius++; // object properties can usually be modified from the outside
myBall.show(); // using the inherited "show" function

Демонстрация функции Variadic ( argumentsэто специальная переменная ):

function sum() {
    let x = 0;

    for (let i = 0; i < arguments.length; ++i)
        x += arguments[i];

    return x;
}

sum(1, 2); // returns 3
sum(1, 2, 3); // returns 6

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

let counter = (function() {
    let i = 0; // private property

    return {   // public methods
        get: function() {
            alert(i);
        },
        set: function(value) {
            i = value;
        },
        increment: function() {
            alert(++i);
        }
    };
})(); // module

counter.get();      // shows 0
counter.set(6);
counter.increment(); // shows 7
counter.increment(); // shows 8

Экспорт и импорт модулей в JavaScript

Пример экспорта:

/* mymodule.js */
// This function remains private, as it is not exported
let sum = (a, b) => {
    return a + b;
}

// Export variables
export let name = 'Alice';
export let age = 23;

// Export named functions
export function add(num1, num2) {
    return num1 + num2;
}

// Export class
export class Multiplication {
    constructor(num1, num2) {
        this.num1 = num1;
        this.num2 = num2;
    }

    add() {
        return sum(this.num1, this.num2);
    }
}

Пример импорта:

// Import one property
import { add } from './mymodule.js';

console.log(add(1, 2)); // 3

// Import multiple properties
import { name, age } from './mymodule.js';
console.log(name, age);
//> "Alice", 23

// Import all properties from a module
import * from './module.js'
console.log(name, age);
//> "Alice", 23
console.log(add(1,2));
//> 3

Более сложный пример

Этот пример кода отображает различные функции JavaScript.

/* Finds the lowest common multiple (LCM) of two numbers */
function LCMCalculator(x, y) { // constructor function
    let checkInt = function(x) { // inner function
        if (x % 1 !== 0)
            throw new TypeError(x + "is not an integer"); // var a =  mouseX

        return x;
    };
    
    this.a = checkInt(x)
    //   semicolons   ^^^^  are optional, a newline is enough
    this.b = checkInt(y);
}
// The prototype of object instances created by a constructor is
// that constructor's "prototype" property.
LCMCalculator.prototype = { // object literal
    constructor: LCMCalculator, // when reassigning a prototype, set the constructor property appropriately
    gcd: function() { // method that calculates the greatest common divisor
        // Euclidean algorithm:
        let a = Math.abs(this.a), b = Math.abs(this.b), t;

        if (a < b) {
            // swap variables
            // t = b; b = a; a = t;
            [a, b] = [b, a]; // swap using destructuring assignment (ES6)
        }

        while (b !== 0) {
            t = b;
            b = a % b;
            a = t;
        }

        // Only need to calculate GCD once, so "redefine" this method.
        // (Actually not redefinition—it's defined on the instance itself,
        // so that this.gcd refers to this "redefinition" instead of LCMCalculator.prototype.gcd.
        // Note that this leads to a wrong result if the LCMCalculator object members "a" and/or "b" are altered afterwards.)
        // Also, 'gcd' === "gcd", this['gcd'] === this.gcd
        this['gcd'] = function() {
            return a;
        };

        return a;
    },

    // Object property names can be specified by strings delimited by double (") or single (') quotes.
    lcm: function() {
        // Variable names do not collide with object properties, e.g., |lcm| is not |this.lcm|.
        // not using |this.a*this.b| to avoid FP precision issues
        let lcm = this.a / this.gcd() * this.b;
        
        // Only need to calculate lcm once, so "redefine" this method.
        this.lcm = function() {
            return lcm;
        };

        return lcm;
    },

    toString: function() {
        return "LCMCalculator: a = " + this.a + ", b = " + this.b;
    }
};

// Define generic output function; this implementation only works for Web browsers
function output(x) {
    document.body.appendChild(document.createTextNode(x));
    document.body.appendChild(document.createElement('br'));
}

// Note: Array's map() and forEach() are defined in JavaScript 1.6.
// They are used here to demonstrate JavaScript's inherent functional nature.
[
    [25, 55],
    [21, 56],
    [22, 58],
    [28, 56]
].map(function(pair) { // array literal + mapping function
    return new LCMCalculator(pair[0], pair[1]);
}).sort((a, b) => a.lcm() - b.lcm()) // sort with this comparative function; => is a shorthand form of a function, called "arrow function"
    .forEach(printResult);

function printResult(obj) {
    output(obj + ", gcd = " + obj.gcd() + ", lcm = " + obj.lcm());
}

Следующий вывод должен отображаться в окне браузера.

LCMCalculator: a = 28, b = 56, gcd = 28, lcm = 56
LCMCalculator: a = 21, b = 56, gcd = 7, lcm = 168
LCMCalculator: a = 25, b = 55, gcd = 5, lcm = 275
LCMCalculator: a = 22, b = 58, gcd = 2, lcm = 638

Безопасность

JavaScript и DOM предоставляют злоумышленникам возможность доставлять сценарии для запуска на клиентском компьютере через Интернет. Авторы браузеров минимизируют этот риск, используя два ограничения. Во-первых, сценарии запускаются в изолированной программной среде, в которой они могут выполнять только действия, связанные с Интернетом, а не задачи программирования общего назначения, такие как создание файлов. Во-вторых, сценарии ограничиваются политикой одного и того же происхождения : сценарии с одного веб-сайта не имеют доступа к такой информации, как имена пользователей, пароли или файлы cookie, отправленные на другой сайт. Большинство ошибок безопасности, связанных с JavaScript, являются нарушением одной и той же политики происхождения или изолированной программной среды.

Существуют подмножества общего JavaScript - ADsafe, Secure ECMAScript (SES) - которые обеспечивают более высокий уровень безопасности, особенно для кода, созданного третьими сторонами (например, рекламы). Closure Toolkit - еще один проект для безопасного встраивания и изоляции стороннего JavaScript и HTML.

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

Межсайтовые уязвимости

Распространенной проблемой безопасности, связанной с JavaScript, является межсайтовый скриптинг (XSS), нарушение политики одного и того же происхождения . XSS-уязвимости возникают, когда злоумышленник может заставить целевой веб-сайт, например веб-сайт онлайн-банкинга, включить вредоносный сценарий на веб-страницу, представленную жертве. Затем сценарий в этом примере может получить доступ к банковскому приложению с привилегиями жертвы, потенциально раскрывая секретную информацию или переводя деньги без разрешения жертвы. Решением XSS-уязвимостей является использование экранирования HTML при отображении ненадежных данных.

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

Уязвимости XSS также могут возникать из-за ошибок реализации авторами браузеров.

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

«Перехват JavaScript» - это тип CSRF-атаки, при которой <script>тег на сайте злоумышленника использует страницу на сайте жертвы, которая возвращает конфиденциальную информацию, такую ​​как JSON или JavaScript. Возможные решения включают:

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

Неуместное доверие к клиенту

Разработчики клиент-серверных приложений должны понимать, что ненадежные клиенты могут находиться под контролем злоумышленников. Автор приложения не может предполагать, что его код JavaScript будет работать должным образом (или вообще), потому что любой секрет, встроенный в код, может быть извлечен определенным противником. Некоторые последствия:

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

Неуместное доверие к разработчикам

Системы управления пакетами, такие как npm и Bower, популярны среди разработчиков JavaScript. Такие системы позволяют разработчику легко управлять зависимостями своей программы от программных библиотек других разработчиков. Разработчики верят, что сопровождающие библиотеки будут держать их в безопасности и обновлять, но это не всегда так. Из-за этого слепого доверия возникла уязвимость. У зависимых библиотек могут быть новые выпуски, которые вызывают ошибки или уязвимости во всех программах, которые полагаются на библиотеки. И наоборот, библиотека может остаться незамеченной из-за известных уязвимостей. В ходе исследования, проведенного на выборке из 133 тыс. Веб-сайтов, исследователи обнаружили, что 37% веб-сайтов содержат библиотеки, по крайней мере, с одной известной уязвимостью. «Среднее отставание между самой старой версией библиотеки, используемой на каждом веб-сайте, и последней доступной версией этой библиотеки в ALEXA составляет 1177 дней, а разработка некоторых библиотек, которые все еще активно используются, прекратилась много лет назад». Другая возможность состоит в том, что сопровождающий библиотеки может полностью удалить библиотеку. Это произошло в марте 2016 года, когда Азер Кочулу удалил свой репозиторий из npm . Это привело к поломке десятков тысяч программ и веб-сайтов, зависящих от его библиотек.

Ошибки кодирования браузера и плагина

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

Эти недостатки затронули основные браузеры, включая Firefox, Internet Explorer и Safari.

Плагины, такие как видеоплееры, Adobe Flash и широкий спектр элементов управления ActiveX, включенных по умолчанию в Microsoft Internet Explorer, также могут иметь недостатки, которые можно использовать с помощью JavaScript (такие недостатки уже использовались в прошлом).

В Windows Vista Microsoft попыталась ограничить риски ошибок, таких как переполнение буфера, запустив процесс Internet Explorer с ограниченными правами. Google Chrome также ограничивает средства визуализации страниц своей собственной «песочницей».

Ошибки реализации песочницы

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

Неправильное предоставление привилегий JavaScript из Интернета сыграло свою роль в появлении уязвимостей как в Internet Explorer, так и в Firefox. В Windows XP с пакетом обновления 2 (SP2) Microsoft снизила права JScript в Internet Explorer.

Microsoft Windows позволяет запускать исходные файлы JavaScript на жестком диске компьютера как универсальные программы без изолированной программной среды (см .: Windows Script Host ). Это делает JavaScript (например, VBScript ) теоретически жизнеспособным вектором для троянского коня , хотя на практике троянские кони JavaScript - редкость.

Аппаратные уязвимости

В 2015 году исследователи в области безопасности описали экспериментальную реализацию атаки Rowhammer на основе JavaScript .

В 2017 году была продемонстрирована атака на основе JavaScript через браузер, способная обойти ASLR . Это называется «ASLR⊕Cache» или AnC.

В 2018 году документ, объявивший об атаках Spectre на спекулятивное выполнение в Intel и других процессорах, включал реализацию JavaScript.

Инструменты разработки

Важные инструменты эволюционировали вместе с языком.

Связанные технологии

Джава

Распространенное заблуждение состоит в том, что JavaScript похож или тесно связан с Java . Верно, что оба имеют синтаксис, подобный C (язык C является их непосредственным общим предком). Они также обычно являются изолированными (при использовании внутри браузера), а JavaScript был разработан с учетом синтаксиса Java и стандартной библиотеки. В частности, все ключевые слова Java были зарезервированы в исходном JavaScript, стандартная библиотека JavaScript следует соглашениям об именах Java, а JavaScript Mathи Dateобъекты основаны на классах из Java 1.0, но на этом сходство заканчивается.

И Java, и JavaScript впервые появились в 1995 году, но Java был разработан Джеймсом Гослингом из Sun Microsystems, а JavaScript - Бренданом Эйхом из Netscape Communications.

Различия между двумя языками более заметны, чем их сходство. В Java используется статическая типизация , а в JavaScript - динамическая . Java загружается из скомпилированного байт-кода, а JavaScript загружается как читаемый человеком исходный код. Объекты Java основаны на классах , а объекты JavaScript - на прототипах . Наконец, Java не поддерживала функциональное программирование до Java 8, в то время как JavaScript поддерживал это с самого начала, находясь под влиянием Scheme .

JSON

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

WebAssembly

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

asm.js - это подмножество JavaScript, которое послужило предшественником WebAssembly.

Транспилеры

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

использованная литература

дальнейшее чтение

  • Фланаган, Дэвид. JavaScript: полное руководство . 7-е издание. Севастополь, Калифорния: О'Рейли, 2020.
  • Хавербеке, Марин. Красноречивый JavaScript . 3-е издание. No Starch Press, 2018. 472 страницы. ISBN  978-1593279509 . (скачать)
  • Закас, Николай. Принципы объектно-ориентированного JavaScript , 1-е издание. No Starch Press, 2014. 120 страниц. ISBN  978-1593275402 .

внешние ссылки

Послушайте эту статью ( 48 минут )
Spoken Wikipedia icon
Этот аудиофайл был создан на основе редакции этой статьи от 20 августа 2013 года и не отражает последующих правок. (2013-08-20)