Партнерка на США и Канаду по недвижимости, выплаты в крипто
- 30% recurring commission
- Выплаты в USDT
- Вывод каждую неделю
- Комиссия до 5 лет за каждого referral
Реферат на тему:
ECMAScript
План:
Введение
- 1 История 2 Семантика и синтаксис
- 2.1 Типы данных 2.2 Инструкции
- 2.2.1 Автодополнение строк точками с запятой 2.2.2 Блоки и область видимости 2.2.3 Объявление переменных
- 2.4.1 Классификация операторов 2.4.2 Особенности операторов ECMAScript
- 2.5.1 Задание функций 2.5.2 Присваивания функций 2.5.3 Перегрузка функций 2.5.4 Рекурсия 2.5.5 Функции обратного вызова 2.5.6 Замыкания
- 2.7.1 Реализация в языке 2.7.2 Синтаксис
- 5.1 Спецификации ECMAScript 5.2 Комментарии 5.3 Стандарты оформления кода JavaScript
Введение
ECMAScript — это встраиваемый расширяемый не имеющий средств ввода/вывода язык программирования, используемый в качестве основы для построения других скриптовых языков[1]. Стандартизирован международной организацией ECMA в спецификации ECMA-262. Расширения языка, JavaScript, JScript и ActionScript, широко используются в вебе.
1. История
Язык возник на основе нескольких технологий, самыми известными из которых являются языки JavaScript и JScript. Разработка первой редакции спецификации началась в ноябре 1996 года. Принятие спецификации состоялось в июне 1997 года. Будучи отправленной в ISO/IEC JTC 1 для принятия по процедуре Fast-Tracking, она послужила основой международного стандарта ISO/IEC 16262. В июне 1998 года общим собранием ECMA была принята вторая редакция ECMA-262, соответствующая ISO/IEC 16262. Третья редакция спецификации отличалась от предыдущей введением поддержки регулярных выражений, улучшением поддержки строк, введением новых управляющих конструкций, механизма исключений, форматирования при численном вводе и некоторые другие изменения[Спецификация 1].
2. Семантика и синтаксис
2.1. Типы данных
В ECMAScript поддерживаются пять примитивных типов данных:
- числовой (англ. Number), строковый (англ. String), логический (англ. Boolean), нулевой (англ. Null), неопределённый (англ. Undefined)[Спецификация 2].
Числовой тип данных в ECMAScript соответствует 64-битному формату чисел с плавающей запятой, определённому стандартом IEEE за исключением того, что различные значения Not-a-Number, определяемые в стандарте[2], представляются в данном языке единственным специальным значением NaN[Спецификация 3].
Нулевой и неопределённый типы данных Дэвидом Флэнаганом неформально причисляются к «тривиальным» типам, поскольку каждый из них определяет только одно значение[3].
Также в языке имеется «составной» тип данных[3]:
- объектный (англ. Object).
Помимо перечисленных шести типов данных в ECMAScript имеется поддержка ещё семи, используемых исключительно для хранения промежуточных результатов вычисляемых выражений:
- ссылочный (англ. Reference), списочный (англ. List), заключительный (англ. Completion). (новый[Спецификация 4][Спецификация 5]) описатель свойства (англ. Property Descriptor), (новый[Спецификация 4][Спецификация 5]) идентификатор свойства (англ. Property Identifier), (новый[Спецификация 4][Спецификация 5]) лексическое окружение (англ. Lexical Environment), (новый[Спецификация 4][Спецификация 5]) запись окружения (англ. Environment Record).
Популярность языка JavaScript и нетривиальность обработки данных, относящихся к разным типам, обусловили развёртывание академических исследований в области анализа типов данных ECMAScript, ставящих своей целью создание полноценного анализатора кода, который можно было бы применять в интегрированных средах разработки[4].
2.2. Инструкции
В ECMAScript имеется пятнадцать различных видов инструкций, данные о которых представлены в таблице ниже:
Типы инструкций, определяемые спецификацией языка[Спецификация 6] | |||
Название | Оригинальное название | Краткие сведения | Завершающая ;[Спецификация 7] |
Блок | англ. Block | {[<инструкции>]} | - |
Объявление переменной | англ. VariableStatement | var <список объявления переменных> | + |
Пустая инструкция | англ. EmptyStatement | ; | + |
Выражение | англ. ExpressionStatement | [строка до ? {{, function}] инструкция | + |
Условие | англ. IfStatement | if (<инструкция>) <выражение>[ else <выражение>] | - |
Цикл | англ. IterationStatement | do <выражение> while (<инструкция>) while (<инструкция>) <выражение> | +/-[~ 1] |
Продолжение | англ. ContinueStatement | continue [<идентификатор>] | + |
Прерывание | англ. BreakStatement | break [<идентификатор>] | + |
Возврат | англ. ReturnStatement | return [<инструкция>] | + |
Сочетание | англ. WithStatement | with (<инструкция>) <выражение> | - |
Метка | англ. LabelledStatement | <идентификатор>: <выражение> | - |
Выбор | англ. SwitchStatement | switch (<инструкция>) case <инструкция>: [<выражения>][ case <инструкция>: [<выражения>] …] [default: [<выражения>]] | - |
Генерация исключения | англ. ThrowStatement | throw <инструкция> | + |
Блок try | англ. TryStatement | try <блок> catch (<идентификатор>) <блок> | - |
(новое[Спецификация 8]) Отладчик | англ. Debugger | debugger | - |
2.2.1. Автодополнение строк точками с запятой
Несмотря на обязательность точки с запятой в случаях, отмеченных в четвёртой колонке, спецификация декларирует механизм автодополнения строк точками с запятой, приводящий к тому, что при наличии переноса строки инструкция до переноса может быть снабжена этим знаком[Спецификация 7], что является объектом критики[5].
Инструкции, меняющие смысл при использования перевода строки внутри[Спецификация 7]
- Унарный постфиксный ++ Унарный постфиксный -- Продолжение Прерывание Возврат Генерация исключения
Пример изменения смысла инструкции
return{
status: "complete"
};
Здесь выделенная строка содержит допустимую языком инструкцию и, поскольку далее следует перевод строки, срабатывает механизм автодополнения строк точками с запятой. Вместо того, функция, содержащая приведённый код, в качестве своего значения вернула объект со свойством status, она вернёт undefined.
Учёт этой особенности языка при выработке стандарта оформления кода может помочь избежать ошибок. Играет роль выбор стиля отступов. В частности, широко распространённые сейчас стили Олмана и Уайтсмита, а также стиль Хорстмана и стиль GNU для кода JavaScript являются менее предпочтимыми, нежели стили K&R, 1TBS, BSD KNF или баннерный стиль.
В стандартах кодирования принято прописывать обязательность проставления точек с запятой даже в тех случаях, когда синтаксис языка позволяет их опускать[Стандарты кодирования 1][Стандарты кодирования 2][Стандарты кодирования 3][Стандарты кодирования 4][Стандарты кодирования 5].
2.2.2. Блоки и область видимости
Ещё одной особенностью ECMAScript по отношению к другим C-подобным языкам является то, что в данном языке блоки не образуют области видимости (англ.). Объявленные в блоке переменные распространяются на всю функцию, содержащую блок[6][7].
В данном участке кода имеет место повторное объявление переменной в выделенных строках:
1.
2. function foo() {
4.
5. var sum = 0;
7.
8. for (var i = 0; i < 42; i += 2) {
10.
11. var tmp = i + 2;
13.
14. sum += i * tmp;
16.
17. }
19.
20. for (var i = 1; i < 42; i += 2) {
22.
23. sum += i*i;
25.
26. }
28.
29. alert(tmp);
31.
32. return sum;
34.
35. }
37.
38. foo();
Кроме того, к переменной tmp, объявленной внутри первого из циклов (строка 5), в соответствии с синтаксисом языка вполне законно обратиться извне цикла (строка 10).
Из-за особенностей, связанных с областью видимости и блоками, в целях поддержания качества исходного кода рекомендуется объявлять переменные в начале функций[6][Стандарты кодирования 1][Стандарты кодирования 4].
2.2.3. Объявление переменных
Переменные определяются с помощью ключевого слова var. При объявлении переменная помещается в область видимости, соответствующую функции, в которой она объявляется. Если переменная объявляется вне функций, она помещается в глобальную область видимости. Создание переменной происходит при получении управления функцией с её объявлением. Или программой, если переменная глобальна. При создании переменной в ECMAScript она приобретает значение undefined. Если переменная объявлена с инициализацией, инициализация происходит не в момент создания переменной, а при выполнении строки с инструкцией var[Спецификация 9].
При раскомментировании выделенной строки на экран будет выводиться не number, а undefined:
var a = 42;
function foo() {
alert(typeof a);
// var a = 10;}
foo();
При создании переменной она приобретает внутреннее свойство {DontDelete} и её невозможно удалить с помощью оператора delete[Спецификация 9]. Исключение составляют переменные, объявленные в контексте eval[8][Спецификация 10].
Многие источники[9][10][11][12][13][14] декларируют возможность неявного объявления переменных в ECMAScript при осуществлении присваивания корректному идентификатору, не являющемуся формальным аргументом функции, без предварительного объявления с помощью var. Однако в терминологии спецификации языка в этом случае создаётся свойство глобального объекта, а не переменная[8][Спецификация 9].
Фиксация в стандарте оформления кода необходимости обязательного объявления переменных до их использования[Стандарты кодирования 1][Стандарты кодирования 4] (либо фиксация необходимости использовать пространства имён для всех глобальных объектов[Стандарты кодирования 2]) позволяет избегать трудноуловимых ошибок, предотвращая опасность взаимодействия одинаково названных переменных в разных участках кода[15].
2.3. Ключевые и зарезервированные слова
Следующие слова являются ключевыми в языке и не могут быть использованы как идентификаторы[Спецификация 11]:
break do instanceof typeof
case else new var
catch finally return void
continue for switch while
debugger function this with
default if throw
delete in try
По сравнению с третьей редакцией спецификации[Спецификация 12] в пятой добавилось ключевое слово debugger с соответствующей инструкцией.
Следующие слова используются как ключевые слова в предложенных расширениях и поэтому являются зарезервированными для возможности адаптировать эти расширения[Спецификация 13]:
class enum extends super
const export import
При использовании строгого режима следующие слова рассматриваются как зарезервированные для использования в будущем[Спецификация 13]:
implements let private public yield
interface package protected static
Таким образом, по сравнению с третьей редакцией спецификации языка количество зарезервированных для использования в будущем слов существенно снизилось. Ранее их было 31[Спецификация 14], и наличие большого количества ключевых и зарезервированных слов, большинство из которых не используется в языке, подвергалось критике[16].
2.4. Операторы
В ECMAScript имеются как операторы, использующие в качестве названий ключевые слова, так и операторы, использующие в качестве названий знаки препинания.
2.4.1. Классификация операторов
По убыванию приоритета операторы ECMAScript можно разбить в следующие группы:
- . (доступ к свойству),[] (доступ к свойству),() (вызов функции), new (создание нового объекта), ++ (инкремент), -- (декремент), - (унарный минус), + (унарный плюс), ~ (поразрядное дополнение), ! (логическое дополнение), delete (удаление свойства), typeof (определение примитивного типа данных), void (возврат неопределённого значения), * (умножение), / (деление), % (остаток от деления), + (сложение), - (вычитание), + (конкатенация строк), << (сдвиг влево), >> (сдвиг вправо с расширением знакового разряда), >>> (сдвиг вправо с дополнением нулями), < (меньше), <= (меньше или равно), > (больше), >= (больше или равно), instanceof (проверка типа объекта), in (проверка наличия свойства), == (проверка на равенство), != (проверка на неравенство), === (проверка на идентичность), !== (проверка на неидентичность), & (поразрядная конъюнкция), ^ (поразрядное сложение по модулю 2), | (поразрядная дизъюнкция), && (конъюнкция), || (дизъюнкция), ?: (тернарная условная операция), = (присваивание), *=, /=, +=, -=, <<=, >=, >>>=, &=, ^=, |= (присваивание с операцией), , (множественное вычисление)[17].
Операторы ++, --, -, +, ~, !, delete, typeof, void, ?:, =, *=, /=, +=, -=, <<=, >=, >>>=, &=, ^=, |= правоассоциативны (то есть для них a op b op c эквивалентно a op (b op c)). Остальные операторы ECMAScript левоассоциативны[18].
По арности операторы ECMAScript делятся на следующие группы:
- унарные (delete, void, typeof, ++, --, - (унарный минус), + (унарный плюс), ~, !, new)[Спецификация 15], бинарные (., [], (), *, /, %, + (сложение), - (вычитание), + (конкатенация строк), <<, >>, >>>, <, <=, >, >=, instanceof, in, ==, !=, ===, !==, &, ^, |, &&, ||, =, *=, /=, +=, -=, <<=, >=, >>>=, &=, ^=, |=, ,), тернарные (?:)[19], операторы, не имеющие фиксированного количества операндов (())[20].
По положению знака операции относительно операндов операторы ECMAScript делятся на следующие группы:
- префиксные (например, new, ++ (префиксный инкремент), инфиксные (например, +, -), постфиксные (например, ++ (постфиксный инкремент), -- (постфиксный декремент).
Также операторы классифицируются по типу операндов[21] и по характеру осуществляемого действия.
2.4.2. Особенности операторов ECMAScript
В ECMAScript нет оператора, позволяющего проверить, относится ли свойство непосредственно к объекту или является унаследованным. Такая проверка осуществляется с помощью метода hasOwnProperty(). В связи с тем, что данный метод не является оператором, он может быть переписан любым другим свойством[22].
Оператор + является единственным арифметическим оператором в языке, который перегружен для строковых аргументов. Если хотя бы один из операндов — строка, + действует как конкатенатор, в противном случае выполняется сложение[23][Спецификация 16].
В отличие от языков, где void является типом данных, в ECMAScript это оператор, возвращающий значение undefined[24].
Оператор == осуществляет проверку на равенство по алгоритму, состоящему из 10 шагов, подразумевающего в ряде случаев преобразование типов[Спецификация 17], что, в конечном счёте, может привести к неочевидным результатам[25].
Пример результатов работы == (во всех перечисленных случаях значением оператора с теми же аргументами будет false):
alert("NaN" == NaN); // false
alert(NaN!= NaN); // true
alert(true == 1); // true
alert(true == 42); // false
alert(null == 0); // false
alert(0 == ""); // true
alert("" == 0); // true
alert("false" == false); // false
alert(false == 0); // true
alert(undefined == false); // false
alert(null == false); // false
alert(undefined == null); // true
alert(" \t\r\n " == 0); // true
2.5. Функции
Функции в ECMAScript являются объектами[26][27]. Конструктор, с помощью которого они создаются — Function(). Функции, как и любые другие объекты, могут храниться в переменных, объектах и массивах, могут передаваться как аргументы в другие функции и могут возвращаться функциями. Функции, как и любые другие объекты, могут иметь свойства. Существенной специфической чертой функций является то, что они могут быть вызваны[26].
2.5.1. Задание функций
В ECMAScript имеется два типа функций:
- внутренние функции (например, parseInt), функции, определённые в тексте программы.
Внутренние функции представляют собой встроенные объекты (см. ниже), не обязательно реализованные на ECMAScript[Спецификация 18].
В тексте программы именованную функцию в ECMAScript можно определить одним из следующих способов:
// объявление функции
function sum(arg1, arg2) {
return arg1 + arg2;
}
// задание функции с помощью инструкции
var sum2 = function(arg1, arg2) {
return arg1 + arg2;
};
// задание функции с использованием объектной формы записи
var sum3 = new Function("arg1", "arg2", "return arg1 + arg2;");
Последний способ наименее предпочтителен, поскольку де-факто сводится к заданию функции с помощью выражения, но при этом порождает двойную интерпретацию кода (дополнительная интерпретация возникает при передаче кода в конструктор), что может негативно отразиться на производительности[27].
Первые два способа дают похожий, но не идентичный эффект. Усугубляет ситуацию то, что инструкция, использующаяся при задании функции может выглядеть очень похоже на объявление функции: во-первых, за ключевым словом function может следовать идентификатор[Спецификация 19], во-вторых, точка с запятой может быть опущена в силу механизма автодополнения строк точками с запятой[Спецификация 7]. Пример:
// объявление функции
function sum(arg1, arg2) {
return arg1 + arg2;
}
// задание функции с помощью выражения
var sum2 = function sum(arg1, arg2) {
return arg1 + arg2;
}
function bar(){}; // использование объявления функции
(function bar(){}) // использование соответствующей инструкции
Наиболее существенной разницей между заданием функции с использованием объявления и заданием функции с помощью выражения является то, что в первом случае создание переменной и присваивание ей в качестве значения функции осуществляются до выполнения кода при входе в контекст исполнения. Во втором случае переменная получает значение инциализатора при выполнении оператора присваивания. При создании же переменной, осуществляемом при входе в контекст исполнения, она инициализируется значением undefined[Спецификация 20][28] (подробнее см. в разделе Объявление переменных).
Пример, иллюстрирующий разницу в порядке выполнения кода:
alert(sum(3, 4)); // 7: переменная sum к моменту выполнения этой строки уже создана и в качестве значения ей присвоена функция
function sum(arg1, arg2) {
return arg1 + arg2;
}
alert(sum2(3, 4)); // ошибка: переменная sum2 к моменту выполнения этой строки уже создана, но в качестве значения ей присвоено undefined
var sum2 = function(arg1, arg2) {
return arg1 + arg2;
};
Объявлением функций не следует пользоваться внутри условных конструкций[29], хотя в Gecko-браузерах это обработается интуитивным образом за счёт реализованного механизма функций как инструкций[30].
2.5.2. Присваивания функций
Поскольку функции в ECMAScript являются объектами, то есть относятся к ссылочному типу данных, идентификаторы функций являются переменными, хранящими ссылку на функцию. Проиллюстрировать это можно следующим кодом:
var sum = function(arg1, arg2) {
return arg1 + arg2;
};
alert(sum(3, 4)); // 7
var sum2 = sum;alert(sum2(4, 2)); // 6
sum = null;
alert(sum2(42, 42)); // 84
В выделенной строке следует обратить внимание на отсутствие оператора вызова функции (()) в правой части присваивания. Если бы в этой строке вместо sum было указано sum(), переменной sum2 присвоилась бы не функция, а результат её вызова. Ещё внимания заслуживает то, что после присваивания sum2 указывает не на копию функции, а на ту самую функцию, на которую указывает sum.
2.5.3. Перегрузка функций
В ECMAScript перегрузка функций не относится к свойствам языка, а её эффект обеспечивается за счёт использования других механизмов.
Пример, показывающий отсутствие перегрузки функций:
function sum(arg1, arg2) {
return arg1 + arg2;
}
function sum(arg1, arg2, arg3) {
return arg1 + arg2 + arg3;
}
alert(sum(3, 4)); // NaN
alert(sum(3, 4, 5)); // 12
Если объявлено несколько функций с одинаковыми названиями, более поздние объявления перезаписывают ранние объявления[27].
Тем не менее, эффект перегрузки функций достижим.
1. Проверка на undefined. Для того, чтобы проверить, передан ли в функцию фактический аргумент, можно осуществить проверку формального аргумента на идентичность значению undefined. Например:
function sum(arg1, arg2, arg3) {
if (arg3 !== undefined) {
return arg1 + arg2 + arg3;
} else {
return arg1 + arg2;
}
}
alert(sum(3, 4)); // 7
alert(sum(3, 4, 5)); // 12
2. Проверка типа. Кроме того, typeof, instanceof, constructor могут быть использованы для выяснения типа фактических аргументов и кастомизации поведения функции в зависимости от них.
function sum(arg1, arg2, arg3) {
switch (typeof arg3) {
case "undefined":
return arg1 + arg2;
case "number":
return arg1 + arg2 + arg3;
default:
return arg1 + arg2 + " (" + arg3 + ")";
}
}
alert(sum(3, 4)); // 7
alert(sum(3, 4, 5)); // 12
alert(sum(3, 4, "!")); // "7 (!)"
3. Обращение к данным об аргументах. В функциях ECMAScript можно получить доступ к данным об аргументах с помощью объекта arguments[Спецификация 21]. Он, в частности, позволяет воспользоваться индексированием для доступа к конкретным переданным аргументам[27][31] и свойством length, хранящем количество фактически переданных аргументов, что может быть полезно при применении парадигмы обобщённого программирования.
function sum() {
var res = 0;
for (var i = 0; i < arguments. length; i++) {
res += arguments[i];
}
return res;
}
alert(sum(3, 4)); // 7
alert(sum(3, 4, 5)); // 12
alert(sum(3, 4, 5, 7, 9)); // 28
2.5.4. Рекурсия
Функции ECMAScript допускают рекурсивный вызов. При задании функции с помощью инструкции без указания идентификатора после ключевого слова function внутри функции можно обратиться к ней с помощью свойства callee объекта arguments[Спецификация 21].
Пример рекурсивного вычисления факториала:
var factorial = function(step, res) {
res = res || 1;
if (step < 2) {
return res;
}
return arguments. callee(step - 1, step * res);
};
alert(factorial(5)); // 120
На данный момент в ECMAScript не реализована хвостовая рекурсия, применяемая для оптимизации рекурсивных вызовов[32].
2.5.5. Функции обратного вызова
В ECMAScript функция представляет собой объект первого класса и может быть передана в другую функцию как аргумент. Если она при этом вызывается в функции, в которую передаётся, то её называют функцией обратного вызова (или callback-функцией). Если при этом передаваемая функция не имеет имени, это анонимная функция обратного вызова (анонимная callback-функция)[33]. Основные причины использования функций обратного вызова:
- избежание именования функции при оперировании с ней (способствует снижению числа глобальных переменных)[33], делегирование вызова функции другой функции (способствует повышению выразительности кода)[33], увеличение быстродействия[33], упрощение оперирования с непродолжительными событиями[34].
Пример функции, возвращающей сумму от результатов выполнения переданной функции над аргументами:
function sumOfResults(callback) {
var result = 0;
for (var i = 1; i < arguments. length; i++) {
result += callback(arguments[i]);
}
return result;
}
var square = function(x) {
return x * x;
};
alert(sumOfResults(square, 3, 4)); // 25
2.5.6. Замыкания
Функциям в ECMAScript присуща лексическая область видимости. Это означает, что область видимости определяется в момент определения функции (в отличие от динамической области видимости, при которой область видимости определяется в момент вызова функции)[35].
При объявлении функции последовательность областей видимости, относящихся к вложенным функциям сохраняется как составляющая состояния функции. То есть в процессе выполнения программы функции, обладающие доступом к локальным переменным объемлющих функций, сохраняют такой доступ на протяжении всего выполнения программы[35].
Механизм замыканий может использоваться для ограничения видимости переменных автономного участка программы с тем, чтобы не возникали конфликты имён при совместном с другим кодом использовании. Для этого код помещается в анонимную функцию, снабжаемую оператором вызова функции.
(function() {
// Участок программы, доступ к переменным которого необходимо изолировать извне.
})();
При этом определённые в участке программы функции становятся вложенными по отношению к добавленной анонимной функции и в них возможно осуществление доступа к локальным переменным анонимной функции (которые до её введения были глобальными). Однако извне анонимной функции доступ к ним осуществить нельзя: результат выполнения функции игнорируется.
Замыкания используются не только для запрещения доступа к ряду переменных, но и к модификации такого доступа. Это достигается с помощью функций, возвращающих другие функции. Пример функции-генератора последовательных чисел:
var uniqueId = function() {
var id = 0;
return function() { return id++; };
}();
var aValue = uniqueId();
var anotherValue = uniqueId();
За счёт использования замыкания доступ к переменной id имеет только функция, которая была присвоена переменной uniqueId.
Пример карринга:
var multNumber = function(arg) {
return function(mul) {
return arg * mul;
};
};
var multFive = multNumber(5);
alert(multFive(7)); //35
Пример создания объекта, позволяющего осуществить доступ к свойству исключительно с помощью своих методов[36]:
var myObject = function() {
var value = 0;
return {
increment: function (inc) {
value += typeof inc === 'number' ? inc : 1;
},
getValue: function ( ) {
return value;
}
}
}();
alert(myObject. value === undefined); // true
alert(myObject. getValue()); // 0
myObject. increment(9)
myObject. increment(7)
alert(myObject. getValue()); // 16
Пользуясь этим приёмом, можно использовать замыкание для эмуляции констант[37].
var getConstant = function() {
var constants = {
UPPER_BOUND: 100,
LOWER_BOUND: -100
};
return function(constantName) {
return constants[constantName];
};
}();
alert(getConstant("LOWER_BOUND")); // -100
2.6. Регулярные выражения
Синтаксис и функциональность регулярных выражений в ECMAScript сформировались под влиянием Perl 5[Спецификация 22] и допускают два вида синтаксиса: литеральный и объектный.
var literalWay = /pattern/flags;
var objectWay = new RegExp(pattern, flags);
В первом случае шаблон (pattern) и флаги (flags) указываются явно, не сопровождаясь дополнительными избыточными синтаксическими знаками: их разделителями служат слеши. Во втором случае шаблон и флаги должны представлять собой переменные, содержащие строковые значения, либо непосредственно строковые значения. Литеральная форма записи предпочтительнее тем, что не требует двойного[~ 2] экранирования метасимволов регулярных выражений, в отличие от объектной формы[38].
В качестве флагов в ECMAScript могут использоваться следующие символы:
Флаги регулярных выражений[38][Спецификация 22] | |
Флаг | Описание |
g | глобальный режим: шаблон применяется ко всем соответствиям в строке, работа регулярного выражения не останавливается после первого найденного соответствия шаблону |
i | игнорирование регистра: при поиске соответствий регистр символов шаблона и строки игнорируются |
m | многострочный режим: строка, содержащая символы перевода строки, трактуется как несколько строк, разделённых символами перевода строки; работа регулярного выражения осуществляется во всех строках |
Каждое регулярное выражение представляет собой объект со следующими свойствами:
Свойства объекта регулярное выражение в ECMAScript[38][Спецификация 22] | ||
Свойство | Тип | Описание |
global | логический | показывает, установлен ли флаг g |
ignoreCase | логический | показывает, установлен ли флаг i |
multiline | логический | показывает, установлен ли флаг m |
lastIndex | числовой | соответствует номеру позиции в строке, в которой обнаружилось совпадение с шаблоном в результате предыдущего применения регулярного выражения или 0, если регулярное выражение ранее не применялось |
source | строковый | строка, соответствующая шаблону регулярного выражения |
Кроме того, для регулярных выражений определены следующие методы:
Методы объекта регулярное выражение в ECMAScript[38][Спецификация 22] | ||
Метод | Тип возвращаемого значения | Описание |
exec(handledString) | объектный (массив) или null | формирует массив подстрок, соответствующих заданному шаблону с учётом выставленных флагов. null, если никакая подстрока не соответствует шаблону |
test(handledString) | логический | true, если нашлась строка, соответствующая шаблону и false в противном случае |
2.7. Объекты
2.7.1. Реализация в языке
Объекты ECMAScript представляют собой неупорядоченные коллекции свойств, каждое из которых имеет один или более атрибутов, которые определяют как может быть использовано свойство — например, если в качестве значения атрибута ReadOnly установлена истина, то любая попытка выполняющегося ECMAScript-кода поменять значение этого свойства останется безрезультатной. Свойства представляют собой контейнеры, инкапсулирующие другие объекты, значения примитивных типов и методы[Спецификация 23].
Атрибуты свойств объектов ECMAScript[Спецификация 24] | |
Название | Описание |
ReadOnly | Свойство является свойством только для чтения. Попытка поменять значение этого свойства, предпринятая в программе, останется безрезультатной. В некоторых случаях значение свойства с установленным атрибутом ReadOnly меняется в силу действий среды расширения языка, поэтому ReadOnly не следует понимать как неизменное |
DontEnum | Свойство не перечисляется циклом for-in |
DontDelete | Попытки удалить это свойство будут проигнорированы |
Internal | Свойство является внутренним. Оно не имеет названия и к нему нельзя получить доступ с помощью аксессоров. Доступ к этим свойствам определяется реализацией языка. |
Объекты ECMAScript подразделяются на базовые (native) и объекты расширения (host). Под базовыми понимаются любые объекты, независимые от окружения, относящегося к расширению языка. Некоторые из базовых объектов являются встроенными (built-in): существующими с самого начала выполнения программы. Другие могут быть созданы, когда программа выполняется. Объекты расширения предоставляются расширением ECMAScript, а для ECMAScript это значит, что они входят в объектную модель документа или в объектную модель браузера[Спецификация 2].
2.7.2. Синтаксис
Для задания объектов может использоваться объектная и литеральная формы. Объектная форма задания объекта имеет синтаксис, аналогичный Java, но, в отличие от него, скобки в ECMAScript требуется использовать только при передаче аргументов в конструктор[39]. Синтаксически следующие записи эквивалентны:
var obj1 = new Object();
var obj2 = new Object;
var obj3 = {};
Однако второй вариант использовать не рекомендуется[39]. Дуглас Крокфорд рекомендует избегать и первого варианта, отдавая предпочтение литеральной форме, которую он считает большим достоинством языка[40].
Спецификация языка оперирует понятием свойства объекта, называя методом использующуюся в качестве свойства объекта функцию[Спецификация 2].
Каждый объект в языке имеет следующие свойства:
Свойства объектов ECMAScript[39] | |
Название | Краткое описание |
constructor | Функция, использованная для создания объекта (в примерах выше это Object()) |
hasOwnProperty(propertyName) | Показывает, существует ли данное свойство в объекте (не в его прототипе) |
isPrototypeOf(object) | Определяет, находится ли объект в цепи прототипов объекта-аргумента |
propertyIsEnumerable(propertyName) | Показывает, является ли свойство с данным названием перечислимым в цикле for-in |
toString() | Возвращает представление объекта в виде строки |
valueOf() | Возвращает значение this. Если же объект является результатом вызова конструктора объекта расширения, значение valueOf() зависит от реализации[Спецификация 2]. Зачастую в качестве возвращаемого значения выступает значение примитивного типа, соответствующее объекту. Как правило, результат данного метода совпадает с результатом toString(). Объекты, созданные с помощью конструктора Date() — яркий пример, где результаты toString() и valueOf() не совпадают[39]. |
Доступ к свойствам объекта осуществляется использованием точечной и скобочной записи:
var obj = new Object();
alert(obj. constructor === obj["constructor"]); // true — использование точечной и скобочной записи для доступа к свойству
var foo = obj["toString"]; // использование скобочной записи для сохранения функции в переменную
var result = obj["toString"](); // сохранение результата вызова функции в переменную
alert(foo()); // вывод на экран результата вызова сохранённой функции
alert(result);
var boo = obj. toString; // аналогично с использованием точечной записи
var res = obj. toString();
alert(boo());
alert(res);
Задание новых свойств может осуществляться динамически.
var country = new Object();
country["name"] = "Russia"; // использование скобочной записи
country. foundationYear = 862; // использование точечной записи
var country2 = {
"name": "Russia",
"foundationYear": 862
}; // использование литеральной формы
2.8. Подходы к созданию объектов
Создание объектов описанным в предыдущем разделе способом может быть непрактичным из-за необходимости дублировать код[41]. Если в программе происходит манипуляция с большим количеством однотипных объектов, разработчик имеет возможность выбрать одну из используемых в языке техник[41]:
фабрика объектов
функция, создающая объект и возвращающая его в качестве своего значения,
конструктор
функция, использующая ключевое слово this для формирования свойств объекта, создаваемого ей с помощью оператора new,
прототипный подход
задействование свойства prototype функции для вынесения общих свойств объектов,
смешанный подход конструктор-прототип
использование конструктора для задания свойств объектов, не являющихся методами и прототипного подхода — для задания методов,
метод динамического прототипа
заключение кода, относящегося к функции создания объектов на основе смешанного подхода конструктор-прототип, в неё одну с обеспечением однократности присваивания свойств прототипа,
метод паразитического конструктора
использование new с функцией фабрики объектов.
В языке нет классов, однако их можно эмулировать за счёт использования конструкторов. Пример эмуляции класса в ECMAScript:
function MyClass() {
this. myValue1 = 1;
this. myValue2 = 2;
}
MyClass. prototype. myMethod = function() {
return this. myValue1 * this. myValue2;
}
var mc = new MyClass();
mc. myValue1 = mc. myValue2 * 2;
var i = mc. myMethod();
2.9. Особенности наследования в ECMAScript
Для каждой из составляющих объекта можно рассматривать наследование. При наследовании интерфейса родителя без того, чтобы потомок использовал функциональность предка, говорят о наследовании интерфейса. При наследовании состояния осуществляется наследование объектом-потомком структуры данных объекта-предка. При наследовании функциональности речь идёт о наследовании вместе с интерфейсом и кода методов. Как правило это влечёт необходимость организации наследования состояния, что делает разумным объединение наследования состояния и наследования функциональности в наследование реализации[42].
В отношении ECMAScript неприменимо лишь наследование интерфейсов, поскольку функции в языке не имеют сигнатур[41].
О возможностях, предоставляемых языком для организации наследования можно судить, например, по приводимому[43] Стояном Стефановым списку из двенадцати разных способов организации наследования.
3. Стандарты ECMAScript
- Standard ECMA-262: ECMAScript Language Specification 5th edition (December 2009) Standard ECMA-290: ECMAScript Components Specification (June 1999) Standard ECMA-327: ECMAScript 3rd Edition Compact Profile (June 2001) Standard ECMA-357: ECMAScript for XML (E4X) Specification 2nd edition (December 2005)


