Знаймо

Додати знання


Цей текст може містити помилки.

ECMAScript



План:


Введення

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 підтримує п'ять примітивних типів даних :

Числовий тип даних в ECMAScript відповідає 64-бітному формату чисел з плаваючою комою, визначеного стандартом IEEE 754-2008 за винятком того, що різні значення Not-a-Number, що визначаються в стандарті [2], представляються в даній мові єдиним спеціальним значенням NaN [Специфікація 3].

Нульовий і невизначений типи даних Девідом Фленаганом неформально зараховуються до "тривіальним" типам, оскільки кожен з них визначає тільки одне значення [3].

Також в мові є "складовою" тип даних [3] :

Крім перерахованих шести типів даних в ECMAScript є підтримка ще семи, що використовуються виключно для зберігання проміжних результатів обчислюваних виразів:

Популярність мови JavaScript і нетривіальність обробки даних, що відносяться до різних типів, зумовили розгортання академічних досліджень в галузі аналізу типів даних ECMAScript, що ставлять своєю метою створення повноцінного аналізатора коду, який можна було б застосовувати в інтегрованих середовищах розробки [4].


2.2. Інструкції

У ECMAScript є п'ятнадцять різних видів посібників, дані про які наведено в таблиці нижче:

Типи інструкцій, визначаються специфікацією мови [Специфікація 6]
Назва Оригінальна назва Короткі відомості Завершальна; [Специфікація 7]
Блок англ. Block {[<Інструкції>]} -
Оголошення змінної англ. VariableStatement var <список оголошення змінних> +
Порожня інструкція англ. EmptyStatement ; +
Вираз англ. ExpressionStatement [Рядок до ∉ {{, function}] інструкція +
Умова англ. IfStatement if (<інструкція>) <вираз> [else <вираз>] -
Цикл англ. IterationStatement do <вираз> while (<інструкція>)

while (<інструкція>) <вираз>
for ([<інструкція до початку>]; [<інструкція>]; [<інструкція>]) <вираз>
for (<оголошення змінних>; [<інструкція>]; [<інструкція>]) <вираз>
for ( in <інструкція>) <вираз>
for (<оголошення змінних> in <інструкція>) <вираз>

+ / - [~ 1]
Продовження англ. ContinueStatement continue [<ідентифікатор>] +
Переривання англ. BreakStatement break [<ідентифікатор>] +
Повернення англ. ReturnStatement return [<інструкція>] +
Поєднання англ. WithStatement with (<інструкція>) <вираз> -
Мітка англ. LabelledStatement <Ідентифікатор>: <вираз> -
Вибір англ. SwitchStatement switch (<інструкція>) case <інструкція>: [<вирази>] [case <інструкція>: [<вирази>] ...] [default: [<вирази>]] -
Генерація виключення англ. ThrowStatement throw <інструкція> +
Блок try англ. TryStatement try <блок> catch (<ідентифікатор>) <блок>
try <блок> finally <блок>
try <блок> catch (<ідентифікатор>) <блок> finally <блок>
-
(Нове [Специфікація 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.  function  foo  (  )  { 
  2.  var  sum  =  0  ; 
  3.  for  (  var  i  =  0  ;  i  <  42  ;  i  + =  2  )  { 
  4.  var  tmp  =  i  +  2  ; 
  5.  sum  + =  i  *  tmp  ; 
  6.  } 
  7.  for  (  var  i  =  1  ;  i  <  42  ;  i  + =  2  )  { 
  8.  sum  + =  i  *  i  ; 
  9.  } 
  10.  alert  (  tmp  )  ; 
  11.  return  sum  ; 
  12.  } 
  13.  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].

(Тобто для них 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


Цей текст може містити помилки.

Схожі роботи | скачати

Схожі роботи:
ECMAScript для XML
© Усі права захищені
написати до нас