Функции - JavaScript

Функции
=======

Сводка
------

В общем случае, функция — это "подпрограмма", которую можно *вызывать* из внешнего (или внутреннего, в случае рекурсии) по отношению к функции кода. Как и сама программа, функция состоит из последовательности инструкций, называемой *телом функции.* Значения могут быть *переданы* в функцию, а функция *вернёт* значение.

В JavaScript функции являются объектами первого класса, то есть: они являются объектами и с ними можно взаимодействовать и передавать их точно так же как любой другой объект. Если быть точным, функции — это объекты `Function`.

Больше подробностей и примеров можно найти в руководстве по функциям в JavaScript.

Описание
--------

Каждая функция в JavaScript — это объект Function. О свойствах и методах объектов Function можно прочитать в статье `Function`.

Функции — это не процедуры. Функция всегда возвращает значение, а процедура может возвращать, а может не возвращать.

Чтобы вернуть значение, отличное от значения по умолчанию, в функции должна быть инструкция `return`, которая указывает, что именно нужно вернуть. Функция без него вернёт значение по умолчанию. В случае конструктора, вызванного с ключевым словом `new`, значение по умолчанию — это значение его параметра `this`. Для остальных функций значением по умолчанию будет `undefined`.

Параметры вызова функции называются *аргументами* функции. Аргументы передаются в функцию *по значению*. Если функция изменяет значение аргумента, это изменение не отражается на глобальном состоянии или вызывающей функции. Однако ссылки на объекты — это тоже значения, и они отличаются тем, что если функция изменяет свойства объекта по ссылке, это изменение видно снаружи функции, как показано в примере ниже.

```js
/\* Объявляем функцию 'myFunc' \*/
function myFunc(theObject) {
  theObject.brand = "Toyota";
}

/\*
 \* Объявляем переменную 'mycar';
 \* создаём и инициализируем новый Object;
 \* приравниваем 'mycar' к ссылке на него
 \*/
var mycar = {
  brand: "Honda",
  model: "Accord",
  year: 1998,
};

/\* Выведет 'Honda' \*/
console.log(mycar.brand);

/\* Передаём ссылку на объект в функцию \*/
myFunc(mycar);

/\*
 \* Выведет 'Toyota', так как значение свойства 'brand'
 \* было изменено внутри функции.
 \*/
console.log(mycar.brand);
```

`Ключевое слово this` не ссылается на функцию, которая выполняется в данный момент, поэтому вы должны обращаться к объектами Function по имени, даже внутри тела самой функции.

Определение функций
-------------------

Есть несколько способов определить функцию:

### Объявление функции (инструкция `function`)

Специальный синтаксис для объявления функций (более подробно: function statement):
```

function name([param[, param[, ... param]]]) {
   statements
}
```

`name`

Имя функции.

`param`

Имя аргумента, передаваемого в функцию. У функции может быть не более 255 аргументов.

`statements`

Инструкции, из которых состоит тело функции.

### Функция-выражение (оператор `function`)

Функция-выражение похожа на определение функции и имеет такой же синтаксис (более подробно: function operator):
```

function [name]([param] [, param] [..., param]) {
   statements
}
```

`name`

Имя функции. Может быть не указано, в таком случае функция становится анонимной.

`param`

Имя аргумента, передаваемого в функцию. У функции может быть не более 255 аргументов.

`statements`

Инструкции, из которых состоит тело функции.

### Стрелочная функция-выражение (=>)

**Примечание:** стрелочные функции являются экспериментальной технологией\*,\* частью спецификации ECMAScript 6 и пока что не поддерживаются всеми браузерами.

Стрелочные функции отличаются более кратким синтаксисом и тем, что они лексически связывают значение своего `this (подробнее об этом в статье Стрелочные функции):`
```

([param] [, param]) => {
   statements
}

param => expression
```

`param`

Имя параметра. Если параметров нет, вместо них нужно поставить (). Если параметров больше одного, их также нужно заключить в ().

`statements or expression`

Если инструкций несколько, их нужно заключить в {}. Для одного выражения фигурных скобок не требуется, а результат этого выражения будет возвращён функцией (то есть` функция x => 3 + 8 вернёт 11).```

### Конструктор `Function`

**Примечание:** Использовать конструктор Function не рекомендуется, так как он принимает тело функции в виде строки, а это может помешать оптимизациям, которые выполняют движки JavaScript, а также привести к другим проблемам.

Объекты `Function` можно создавать с помощью оператора `new` (как и любые другие объекты):
```

new Function (arg1, arg2, ... argN, functionBody)
```

`arg1, arg2, ... argN`

Ноль или больше имён параметров функции. Имя должно быть строкой, содержащей валидный идентификатор JavaScript. Если параметров несколько, они должны быть разделены запятыми. Например: "`x`", "`theValue`", или "`a,b`".

`functionBody`

Инструкции, из которых состоит тело функции.

Конструктор `Function` можно вызывать и без оператора `new,` эффект будет тем же.

Параметры функции
-----------------

**Примечание:** Остаточные параметры и параметры по умолчанию *— это экспериментальная* технология, часть спецификации ECMAScript 6, и они пока ещё не получили широкой поддержки среди браузеров.

### Параметры по умолчанию

Параметры функции по умолчанию позволяют инициализировать формальные параметры со значениями по умолчанию, если им не было передано значение, или было передано `undefined`. Подробнее о них можно узнать в статье Параметры по умолчанию.

### Остаточные параметры

Синтаксис оставшихся параметров позволяет передать бесконечное число аргументов как массив. Подробности можно найти в статье Остаточные параметры.

Объект `arguments`
------------------

Внутри функции получить доступ к её аргументам можно через объект arguments.

* `arguments` (en-US): Объект, похожий на массив и содержащий все аргументы, переданные в текущую функцию.
* `arguments.callee` (en-US)
Устарело
: Функция, исполняемая в текущий момент.
* `arguments.caller` : Функция, которая вызвала текущую функцию.
* `arguments.length` (en-US): Число аргументов, переданных в функцию.
Определение методов
-------------------

### Геттеры и сеттеры

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

get

Связывает свойство объекта с функцией, которая будет вызвана при обращении к свойству.

set

Связывает свойство объекта с функцией, которая будет вызвана при попытке изменения свойства.

### Синтаксис определения методов

**Примечание:** *Определение методов — это экспериментальная* технология, часть спецификации ECMAScript 6, и она пока ещё не получила широкой поддержки среди браузеров.

Начиная с ECMAScript 6, можно определять собственные методы, используют более краткий синтаксис, похожий на геттеры и сеттеры. Более подробно — в статье Определение методов.

```js
var obj = {
  foo() {},
  bar() {},
};
```

Сравнение конструкторов `Function` с объявлением функций и функциями-выражениями
--------------------------------------------------------------------------------

Посмотрите на следующие примеры:

Функция, определённая через конструктор `Function` и приравненная к переменной `multiply:`

```js
var multiply = new Function("x", "y", "return x \* y");
```

Объявление функции multiply:

```js
function multiply(x, y) {
  return x \* y;
}
```

Анонимная функция-выражение, приравненная к переменной `multiply:`

```js
var multiply = function (x, y) {
  return x \* y;
};
```

*Функция-выражение* с именем `func_name`, приравненное к переменной `multiply:`

```js
var multiply = function func\_name(x, y) {
  return x \* y;
};
```

### Отличия

Во всех случаях результат примерно одинаков, но есть несколько нюансов:

Имя функции и переменная, к которой функция приравнена — это не одно и то же. Имя функции нельзя менять, а вот переменной, к которой приравнена функция, можно дать другое значение. В случае функции-выражения с именем, это имя может быть использовано только внутри самой функции. При попытке использовать его снаружи возникнет ошибка (а если ранее была объявлена переменная с таким именем, будет возвращено `undefined`). Например:

```js
var y = function x() {};
alert(x); // выкинет ошибку
```

Также имя функции-выражения проявляется, если сериализовать функцию через метод Function.toString.

А вот переменная, к которой функция приравнена, ограничена только собственной областью видимости, которая включает ту область, где функция была объявлена.

Как показано в четвёртом примере, имя функции может отличаться от имени переменной, к которой функция приравнена, эти имена никак не связаны. Объявление функции (function declaration) также создаёт и переменную с именем, аналогичным имени функции. Таким образом:

1. Если функция определена с помощью функции-выражения (function expression), её имя доступно только внутри самой функции.
2. Если функция объявлена (function declaration), её имя доступно в той области видимости, где функция была определена.

У функции, определённой с помощью '`new Function'`, нет имени. Однако, в JavaScript движке SpiderMonkey, сериализованное представление функции отображается так, как будто оно имеет имя "anonymous". Например, , `alert(new Function())` выдаст:

```js
function anonymous() {}
```

Так как на самом деле у функции нет имени, переменную `anonymous` нельзя использовать внутри функции. Например, следующий пример выкинет ошибку:

```js
var foo = new Function("alert(anonymous);");
foo();
```

В отличии от функций, определённых через функцию-выражение или конструктор `Function`, функция, определённая через объявление, может быть использована перед тем, как была определена. Например:

```js
foo(); // выведет FOO!
function foo() {
  alert("FOO!");
}
```

Функция, определённая через функцию-выражение, наследует текущую область видимости, то есть создаёт замыкание. А вот функция, созданная с помощью конструктора `Function`, не наследует ничего, кроме глобальной области видимости (её наследуют вообще все функции).

Функции, определённые через функцию-выражение и объявление функции парсятся только один раз, в отличии от функций, созданных с помощью конструктора. То есть строка, которая передаётся в конструктор `Function`, парсится при каждом вызове конструктора. И хотя функция-выражение каждый раз создаёт замыкание, тело функции при этом не парсится, и получается, что функции-выражение всё равно быстрее, чем "`new Function(...)`". Поэтому конструктора `Function` в большинстве случаев стоит избегать, если это возможно.

Стоит отметить, что функции-выражения и объявления функций внутри функции, созданной при парсинге конструктора `Function`, парсятся только один раз. Например:

```js
var foo = new Function(
  "var bar = 'FOO!';\nreturn(function() {\n\talert(bar);\n});",
)();
foo(); // "function() {\n\talert(bar);\n}" Эта часть строки, составляющей тело функции, не парсится во второй раз.
```

Объявление функции можно очень легко (и часто случайно) превратить в функцию-выражение. Объявление функции перестаёт быть таковым, если оно:

* становится частью выражения
* не является "исходным элементом" функции или файла. Исходный элемент - это не вложенный элемент внутри функции или скрипта:

```js
var x = 0; // исходный элемент
if (x == 0) {
  // исходный элемент
  x = 10; // не исходный элемент
  function boo() {} // не исходный элемент
}
function foo() {
  // исходный элемент
  var y = 20; // исходный элемент
  function bar() {} // исходный элемент
  while (y == 10) {
    // исходный элемент
    function blah() {} // не исходный элемент
    y++; // не исходный элемент
  }
}
```

### Примеры

```js
// объявление функции
function foo() {}

// функция-выражение
(function bar() {});

// функция-выражение
x = function hello() {};

if (x) {
  // функция-выражение
  function world() {}
}

// объявление функции
function a() {
  // объявление функции
  function b() {}
  if (0) {
    // функция-выражение
    function c() {}
  }
}
```

Определение функции в зависимости от условия
--------------------------------------------

Функции могут быть определены в зависимости от условий с помощью инструкции `function (разрешённое расширение стандарта` ECMA-262 Edition 3) или конструктора `Function`. Обратите внимание, что подобные инструкции запрещены в ES5 strict. Кроме того, эта возможность по-разному ведёт себя в разных браузерах, поэтому не стоит на неё рассчитывать.

В коде ниже функция `zero` никогда не будет определена и не может быть вызвана, потому что '`if (0)`' всегда расценивается как `false`:

```js
if (0) {
  function zero() {
    document.writeln("This is zero.");
  }
}
```

Если изменить условие на '`if (1)`', функция `zero` будет определена.

Заметьте, что хотя это выглядит как объявление функции, на самом деле, это функция-выражение (или инструкция), так как она вложена внутрь другой инструкции. Изучите разницу между объявлением функции и функцией-выражением.

Некоторые JavaScript-движки (но не SpiderMonkey), неверно считают любую функцию-выражение с именем за объявление функции. Это приводит к тому, что функция `zero` будет определена, даже если условие всегда `false`. Более безопасный способ определить функцию по условию - это сделать её анонимной и приравнять к переменной:

```js
if (0) {
  var zero = function () {
    document.writeln("This is zero.");
  };
}
```

Примеры
-------

### Пример: возврат отформатированного числа

Эта функция возвращает строку, содержащую число с заданным количеством нулей перед ним:

```js
function padZeros(num, totalLen) {
  var numStr = num.toString(); // Инициализировать возвращаемое значение в виде строки
  var numZeros = totalLen - numStr.length; // Посчитать число нулей в начале
  for (var i = 1; i <= numZeros; i++) {
    numStr = "0" + numStr;
  }
  return numStr;
}
```

Вызовем `padZeros`:

```js
var result;
result = padZeros(42, 4); // возвращает "0042"
result = padZeros(42, 2); // возвращает "42"
result = padZeros(5, 4); // возвращает "0005"
```

### Пример: существует ли функция

Можно определить, существует ли функция с помощью оператора `typeof`. В следующем примере проверяется, есть ли у объекта `window` функция `noFunc`. Если есть, то она вызывается; если нет, выполняется какое-то другое действие.

```js
if ("function" == typeof window.noFunc) {
  // вызывать noFunc()
} else {
  // сделать что-то другое
}
```

Заметьте, что в проверке условия используется ссылка на `noFunc` — после имени функции нет скобок, поэтому сама функция не вызывается.

Спецификации
------------

| Specification |
| --- |
| ECMAScript Language Specification # sec-function-definitions |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* `Function`
* Инструкция `function`
* Оператор `function`


Висящие запятые - JavaScript

Висящие запятые
===============

**Висящие запятые** (или "последние запятые") могут быть полезны при добавлении новых элементов, параметров или свойств в код JavaScript. Если вы хотите добавить новое свойство, вы просто добавляете новую строчку без изменения предыдущей, если в ней уже использована висящая запятая. Это делает различия в контроле версий чище и изменение кода может быть менее хлопотным.

JavaScript с самого начала допускает использовать висящих запятых в литералах массива, а затем добавлял их в литералы объекта (ECMAScript 5) и, совсем недавно (ECMAScript 2017), к параметрам функций.

JSON, однако, не допускает висящих запятых.

Висящие запятые в литералах
---------------------------

### Массивы

JavaScript игнорирует висящие запятые в массивах:

```js
var arr = [1, 2, 3,];

arr; // [1, 2, 3]
arr.length; // 3
```

Если использовано больше одной висящей запятой, будут созданы "дырки". Массив с "дырками" называется *разреженным* (*плотный* массив не имеет "дырок"). При итерации массива при помощи, например, `Array.prototype.forEach()` или `Array.prototype.map()`, "дырки" будут пропущены.

```js
var arr = [1, 2, 3, , ,];
arr.length; // 5
```

### Объекты

Начиная с ECMAScript 5, висящие запятые в объектах также допустимы:

```js
var object = {
  foo: "bar",
  baz: "qwerty",
  age: 42,
};
```

Висящие запятые в функциях
--------------------------

ECMAScript 2017 допускает висящие запятые в списке параметров функции.

### Определение параметров

Следующие определения параметров функций допустимы и равнозначны друг другу. Висящие запятые не влияют на свойство `length` функции или их объект `arguments`.

```js
function f(p) {}
function f(p,) {}

(p) => {};
(p,) => {};
```

Висящая запятая также работает с определением методов для классов или объектов:

```js
class C {
  one(a,) {},
  two(a, b,) {},
}

var obj = {
  one(a,) {},
  two(a, b,) {},
};
```

### Вызов функции

Следующие вызовов функций допустимы и равнозначны друг другу.

```js
f(p);
f(p,);

Math.max(10, 20);
Math.max(10, 20,);
```

### Недопустимые висящие запятые

Определение параметров функции или вызов функции, содержащих только запятую будет генерировать `SyntaxError`. Кроме того, при использовании остаточных параметров не допускается использовать висящие запятые:

```js
function f(,) {} // SyntaxError: missing formal parameter
(,) => {};       // SyntaxError: expected expression, got ','
f(,)             // SyntaxError: expected expression, got ','

function f(...p,) {} // SyntaxError: parameter after rest parameter
(...p,) => {}        // SyntaxError: expected closing parenthesis, got ','
```

Висящие запятые в деструктурировании
------------------------------------

Висящие запятые так же можно использовать слева при использовании деструктурирующего присваивания:

```js
// массив деструктурируется с висящей запятой
[a, b,] = [1, 2];

// объект деструктурируется с висящей запятой
var o = {
  p: 42,
  q: true,
};
var { p, q } = o;
```

Ещё раз, при использовании оставшихся параметров будет сгенерирована `SyntaxError`:

```js
var [a, ...b,] = [1, 2, 3];
// SyntaxError: rest element may not have a trailing comma
```

Висящие запятые в JSON
----------------------

Висящие запятые в объекте допустимы только в ECMAScript 5. Так как JSON основан на синтаксисе JavaScript старше, чем ES5, **висящие запятые не допускаются в JSON**.

Обе строки генерируют `SyntaxError`:

```js
JSON.parse("[1, 2, 3, 4, ]");
JSON.parse('{"foo" : 1, }');
// SyntaxError JSON.parse: unexpected character
// at line 1 column 14 of the JSON data
```

Опустите висящие запятые, чтобы правильно проанализировать JSON:

```js
JSON.parse("[1, 2, 3, 4 ]");
JSON.parse('{"foo" : 1 }');
```

Спецификации
------------

| Specification |
| --- |
| ECMAScript Language Specification # prod-Elision |
| ECMAScript Language Specification # prod-ObjectLiteral |
| ECMAScript Language Specification # prod-ArrayLiteral |
| ECMAScript Language Specification # prod-Arguments |
| ECMAScript Language Specification # prod-FormalParameters |
| ECMAScript Language Specification # prod-CoverParenthesizedExpressionAndArrowParameterList |
| ECMAScript Language Specification # prod-NamedImports |
| ECMAScript Language Specification # prod-NamedExports |
| ECMAScript Language Specification # prod-QuantifierPrefix |
| ECMAScript Language Specification # prod-annexB-InvalidBracedQuantifier |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* Initial ECMAScript proposal: trailing function commas by Jeff Morrison


Strict mode - JavaScript

Strict mode
===========

Режим *strict* (*строгий* режим), введённый в ECMAScript 5, позволяет использовать более строгий вариант JavaScript. Это не просто подмножество языка: в нем сознательно используется семантика, отличающаяся от обычно принятой. Не поддерживающие строгий режим браузеры будут по-другому выполнять код, написанный для строгого режима, поэтому не полагайтесь на строгий режим без тестирования поддержки используемых особенностей этого режима. Строгий и обычный режим могут сосуществовать одновременно, а скрипт может переключаться в строгий режим по мере надобности.

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

Если вы хотите изменить свой код так, чтобы он работал в строгой версии JavaScript, посмотрите статью `Переход к строгому режиму` (en-US).

Активизация строгого режима
---------------------------

Строгий режим применяется ко *всему скрипту* или к *отдельным функциям*. Он не может быть применён к блокам операторов, заключённых в фигурные скобки — попытка использовать его в подобном контексте будет проигнорирована. Код в `eval`, `Function`, в атрибутах обработчиков событий, в строках, переданных в `setTimeout`, и т.п. рассматривается как законченный скрипт, и активизация строгого режима в нём выполняется ожидаемым образом.

### Строгий режим для скриптов

Чтобы активизировать строгий режим для всего скрипта, нужно поместить оператор `"use strict";` или `'use strict';` перед всеми остальными операторами скрипта (выдержать приведённый синтаксис буквально).

```js
// Синтаксис переключения в строгий режим всего скрипта
"use strict";
var v = "Привет! Я скрипт в строгом режиме!";
```

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

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

### Строгий режим для функций

Аналогично, чтобы включить строгий режим для функции, поместите оператор `"use strict";` (или `'use strict';`) в тело функции перед любыми другими операторами.

```js
function strict() {
  // Строгий режим на уровне функции
  "use strict";
  function nested() {
    return "И я тоже!";
  }
  return "Привет! Я функция в строгом режиме! " + nested();
}
function notStrict() {
  return "Я не strict.";
}
```

### Строгий режим для модулей

ECMAScript 2015 представил модули JavaScript и, следовательно, 3-й способ войти в строгий режим. Все содержимое модулей JavaScript автоматически находится в строгом режиме, и для его запуска не требуется никаких инструкций.
```

function strict() {
    // Потому что это модуль, я strict по умолчанию
}
export default strict;
```

Изменения в строгом режиме
--------------------------

Строгий режим изменяет синтаксис и поведение среды исполнения. Изменения главным образом попадают в следующие категории: преобразование ошибок в исключения; изменения, упрощающие вычисление переменной в определённых случаях использования её имени; изменения, упрощающие `eval` и `arguments`; изменения, упрощающие написание "безопасного" JavaScript, и изменения, предвосхищающие дальнейшее развитие ECMAScript.

### Преобразование ошибок в исключения

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

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

```js
"use strict";
// Предполагая, что не существует глобальной переменной
mistypeVaraible = 17; // mistypedVaraible, эта строка выбросит ReferenceError
// из-за опечатки в имени переменной
```

Во-вторых, строгий режим заставляет присваивания, которые всё равно завершились бы неудачей, выбрасывать исключения. Например, `NaN` — глобальная переменная, защищённая от записи. В обычном режиме присваивание `NaN` значения ничего не делает; разработчик не получает никакого сообщения об ошибке. В строгом режиме присваивание `NaN` значения выбрасывает исключение. Любое присваивание, которое в обычном режиме завершается неудачей (присваивание значения свойству, защищённому от записи; присваивание значения свойству, доступному только на чтение; присваивание нового свойства нерасширяемому объекту), в строгом режиме выбросит исключение:

```js
"use strict";

// Присваивание значения глобальной переменной, защищённой от записи
var undefined = 5; // выдаст TypeError
var Infinity = 5; // выдаст TypeError

// Присваивание значения свойству, защищённому от записи
var obj1 = {};
Object.defineProperty(obj1, "x", { value: 42, writable: false });
obj1.x = 9; // выдаст TypeError

// Присваивание значения свойству, доступному только для чтения
var obj2 = {
  get x() {
    return 17;
  },
};
obj2.x = 5; // выдаст TypeError

// Задание нового свойства нерасширяемому объекту
var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // выдаст TypeError
```

В-третьих, в строгом режиме попытки удалить неудаляемые свойства будут вызывать исключения (в то время как прежде такая попытка просто не имела бы эффекта):

```js
"use strict";
delete Object.prototype; // выдаст TypeError
```

В-четвёртых, строгий режим требует, чтобы все свойства, перечисленные в сериализованном объекте, встречались только один раз. В обычном коде имена свойств могут дублироваться, а значение свойства определяется последним объявлением. Но, в таком случае, дублирование — просто почва для багов, если код редактируется с тем, чтобы поменять значение свойства как-то по-другому, кроме изменения последнего объявления. Дублирование имён свойств в строгом режиме является синтаксической ошибкой:

**Примечание:** Это уже не является проблемой в ECMAScript 2015 (Firefox bug 1041128).

```js
"use strict";
var o = { p: 1, p: 2 }; // !!! синтаксическая ошибка
```

В-пятых, строгий режим требует, чтобы имена аргументов в объявлении функций встречались только один раз. В обычном коде последний повторённый аргумент скрывает предыдущие аргументы с таким же именем. Эти предыдущие аргументы всё ещё доступны через `arguments[i]`, так что они не полностью потеряны. Тем не менее, такое сокрытие несёт в себе мало смысла и, скорее всего, не имеет под собой цели (например, может скрывать опечатку), поэтому в строгом режиме дублирование имён аргументов является синтаксической ошибкой:

```js
function sum(a, a, c) {
  // !!! синтаксическая ошибка
  "use strict";
  return a + a + c; // ошибка, если код был запущен
}
```

В-шестых, строгий режим запрещает синтаксис восьмеричной системы счисления. Восьмеричный синтаксис не является частью ECMAScript, но поддерживается во всех браузерах с помощью дописывания нуля спереди к восьмеричному числу: `0644 === 420` и `"\045" === "%"`. В ECMAScript 2015 восьмеричное число поддерживается также с помощью дописывания перед числом "`0o`". Т.е.
```

var a = 0o10; // ES2015: Восмеричное
```

Иногда начинающие разработчики думают, что ведущий ноль не имеет семантического значения, и используют его для выравнивания — но это меняет значение числа! Восьмеричный синтаксис редко бывает полезен и может быть неправильно использован, поэтому строгий режим считает восьмеричные числа синтаксической ошибкой:

```js
"use strict";
var sum =
  015 + // !!! синтаксическая ошибка
  197 +
  142;

var sumWithOctal = 0o10 + 8;
console.log(sumWithOctal); // 16
```

В-седьмых, строгий режим в ECMAScript 2015 запрещает установку свойств primitive значениям. Без строгого режима, установка свойств просто игнорируется (no-op), со строгим режимом, однако, выдаёт `TypeError`.
```

(function() {
'use strict';

false.true = '';         // TypeError
(14).sailing = 'home';   // TypeError
'with'.you = 'far away'; // TypeError

})();
```

### Упрощение работы с переменными

Строгий режим упрощает сопоставление имени переменной с местом её определения в коде. Многие оптимизации времени компиляции полагаются на возможность считать, что переменная *X* хранится в *этом конкретном* месте исходного кода. Иногда, при компиляции JavaScript простое сопоставление имени переменной с местом её определения в коде не возможно, без выполнения того самого кода. Строгий же режим исключает большинство таких случаев, благодаря чему оптимизации компилятора работают эффективнее.

Во-первых, строгий режим запрещает использование `with`. Проблема с `with` в том, что во время выполнения любое имя внутри блока может ссылаться как на свойство обрабатываемого объекта, так и на переменную в окружающем (или даже в глобальном) контексте — невозможно знать об этом заранее. Строгий режим считает `with` синтаксической ошибкой, поэтому не остаётся шанса использовать имя переменной внутри `with` для ссылки на неизвестное место во время выполнения:

```js
"use strict";
var x = 17;
with (obj) {
  // !!! синтаксическая ошибка
  // Если код не в строгом режиме, то будет ли x ссылаться на переменную var x, или
  // на свойство obj.x? Предугадать без запуска кода невозможно,
  // следовательно такой код не может быть эффективно оптимизирован.
  x;
}
```

Простая альтернатива `with` уже существует — присваивание объекта переменной с коротким именем и затем доступ к нужному свойству как свойству этой переменной.

Во-вторых, `eval` в строгом режиме не добавляет новых переменных в окружающий контекст. В обычном режиме, при вызове `eval("var x;")` переменная `x` добавится в область видимости окружающей функции либо в глобальный контекст. В общем случае, это означает, что в каждой функции, в которой присутствует вызов `eval`, имена переменных которые не ссылаются на аргумент или локальную переменную, должны сопоставляться с местом их определения в коде только во время выполнения (потому что `eval` мог ввести новую переменную, которая может перекрыть внешнюю переменную). В строгом режиме `eval` создаёт переменные только в контексте выполняемого кода, так что `eval` не может повлиять на то, ссылается ли имя на локальную или на внешнюю переменную:

```js
var x = 17;
var evalX = eval("'use strict'; var x = 42; x");
console.assert(x === 17);
console.assert(evalX === 42);
```

Соответственно, если функция `eval` вызвана непосредственно в форме выражения `eval(...)`, то внутри кода в строгом режиме, передаваемый в неё код будет выполнен в строгом режиме. Передаваемый код может содержать в себе включение строгого режима, но в этом нет необходимости.

```js
function strict1(str) {
  "use strict";
  return eval(str); // str будет выполнен как код строгого режима
}
function strict2(f, str) {
  "use strict";
  return f(str); // не eval(...): str выполнится в строгом режиме только в том
  // случае, если в нем содержится вызов строгого режима
}
function nonstrict(str) {
  return eval(str); // str выполнится в строгом режиме только в том
  // случае, если в нем содержится вызов строгого режима
}
strict1("'Строгий режим!'");
strict1("'use strict'; 'Строгий режим!'");
strict2(eval, "'Не строгий режим.'");
strict2(eval, "'use strict'; 'Строгий режим!'");
nonstrict("'Не строгий режим.'");
nonstrict("'use strict'; 'Строгий режим!'");
```

Таким образом, имена в строгом коде, передаваемом в `eval`, ведут себя так же, как имена в нестрогом коде, передаваемом в `eval` внутри строгого режима.

В-третьих, строгий режим запрещает удаление простых имён. `delete name` в строгом режиме является синтаксической ошибкой:

```js
"use strict";

var x;
delete x; // !!! синтаксическая ошибка

eval("var y; delete y;"); // !!! синтаксическая ошибка
```

### Упрощение `eval` и `arguments`

В строгом режиме снижается количество странностей в поведении `arguments` и `eval`, оба из которых примешивают определённое количество магии в обычный код. Так `eval` добавляет или удаляет переменные и меняет их значения, а переменная `arguments` может удивить своими проиндексированными свойствами, которые являются ссылками (синонимами) для поименованных аргументов функции. Строгий режим делает большой шаг в прояснении этих двух ключевых слов, но полное их обуздание произойдёт лишь в следующей редакции ECMAScript.

Во-первых, ключевые слова `eval` и `arguments` не могут быть переопределены или изменены. Все подобные попытки это сделать являются синтаксическими ошибками:

```js
"use strict";
eval = 17;
arguments++;
++eval;
var obj = { set p(arguments) {} };
var eval;
try {
} catch (arguments) {}
function x(eval) {}
function arguments() {}
var y = function eval() {};
var f = new Function("arguments", "'use strict'; return 17;");
```

Во-вторых, в строгом режиме поля объекта `arguments` не связаны с проименованными аргументами функции, а являются их продублированными копиями значений. В обычном коде внутри функции, первым аргументом которой является `arg`, изменение значения переменной `arg` также меняет значение и у поля `arguments[0]`, и наоборот (кроме случаев, когда аргумент в функцию не передан, или `arguments[0]` удалён). В строгом режиме `arguments` хранит копии значений аргументов переданных при вызове функции. `arguments[i]` не отслеживает изменений соответствующего именованного аргумента, и именованный аргумент не отслеживает значение соответствующего arguments[i].

```js
function f(a) {
  "use strict";
  a = 42;
  return [a, arguments[0]];
}
var pair = f(17);
console.assert(pair[0] === 42);
console.assert(pair[1] === 17);
```

В-третьих, свойство `arguments.callee` больше не поддерживается. В обычном коде свойство `arguments.callee` ссылается на саму функцию для вызова которой и был создан объект `arguments`. Малоприменимое свойство, так как функция заранее известна, и к ней можно обратиться и по её имени непосредственно. Более того, `arguments.callee` значительно затрудняет такую оптимизацию, как инлайнинг, потому как должна быть сохранена возможность обратиться к незаинлайненой функции на случай, если присутствует обращение к arguments.callee. В строгом режиме arguments.callee превращается в неудаляемое свойство, которое выбрасывает предостерегающее исключение при любой попытке обращения к нему:

```js
"use strict";
var f = function () {
  return arguments.callee;
};
f(); // выдаст TypeError
```

### "Безопасный" JavaScript

Строгий режим упрощает написание "безопасного" JavaScript-кода. Сейчас некоторые веб-сайты предоставляют пользователям возможность писать JavaScript, который будет выполняться на сайте *от имени других пользователей.* В браузерах, JavaScript может иметь доступ к приватной информации пользователя, поэтому, в целях ограничения доступа к запретной функциональности, такой JavaScript перед выполнением должен быть частично преобразован. Гибкость JavaScript делает это практически невозможным без многочисленных проверок во время исполнения. Функционал, исполняемый языком иногда столь массивен, что выполнение любых дополнительных проверок во время исполнения скрипта приведёт к значительной потере производительности. Однако, некоторые особенности строгого режима, плюс обязательное требование того, чтобы JavaScript, загруженный пользователем, имел строгий режим и вызывался определённым способом, существенно снижают потребность в таких проверках.

Во-первых, значение, передаваемое в функцию как `this`, в строгом режиме не приводится к объекту (не "упаковывается"). В обычной функции `this` всегда представляет собой объект: либо это непосредственно объект, в случае вызова с `this`, представляющим объект-значение; либо значение, упакованное в объект, в случае вызова с `this` типа Boolean, string, или number; либо глобальный объект, если тип `this` это `undefined` или `null`. (Для точного определения конкретного `this` используйте ``call``, ``apply``, или ``bind``.) Автоматическая упаковка не только снижает производительность, но и выставляет на показ глобальный объект, что в браузерах является угрозой безопасности, потому что глобальный объект предоставляет доступ к функциональности, которая должна быть ограничена в среде "безопасного" JavaScript. Таким образом, для функции в строгом режиме точно определённый `this` не упаковывается в объект, а если не определён точно, `this` является `undefined`:

```js
"use strict";
function fun() {
  return this;
}
console.assert(fun() === undefined);
console.assert(fun.call(2) === 2);
console.assert(fun.apply(null) === null);
console.assert(fun.call(undefined) === undefined);
console.assert(fun.bind(true)() === true);
```

Во-вторых, в строгом режиме больше не представляется возможным осуществлять "прогонку" стека JavaScript посредством базовых расширений ECMAScript. В обычном коде, использующем эти расширения, когда функция `fun` находится в процессе своего вызова, `fun.caller` представляет собой функцию, вызвавшую `fun`, а `fun.arguments` это `аргументы` для данного вызова `fun`. Оба расширения являются проблемными для "безопасного" JavaScript, так как они позволяют "безопасному" коду получить доступ к "привилегированным" функциям и их (потенциально небезопасным) аргументам. Если `fun` находится в строгом режиме, то `fun.caller`, так же как и `fun.arguments,` представляют собой неудаляемые свойства, которые приведут к вызову исключения при попытке их чтения или записи:

```js
function restricted() {
  "use strict";

  restricted.caller; // выдаст TypeError
  restricted.arguments; // выдаст TypeError
}
function privilegedInvoker() {
  return restricted();
}
privilegedInvoker();
```

В-третьих, в функциях строгого режима свойство `arguments` больше не предоставляет доступ к переменным, созданным внутри функции. В некоторых предыдущих реализациях ECMAScript `arguments.caller` представлял собой объект, свойства которого являлись ссылками на переменные, созданные внутри функции при её вызове. Это представляет собой угрозу безопасности, так как нарушает возможность скрывать приватные данные внутри функций (замыканий). Также это делает невозможными большинство оптимизаций. Исходя из этих причин, ни один из современных браузеров не реализует этого поведения. Но всё же, ввиду своей исторической функциональности, `arguments.caller` для функций в строгом режиме всё ещё является неудаляемым свойством, которое вызывает исключение при попытке его чтения или записи:

```js
"use strict";
function fun(a, b) {
  "use strict";

  var v = 12;
  return arguments.caller; // выдаст TypeError
}
fun(1, 2); // не выводит v (или a, или b)
```

### Подготовка почвы для будущих версий ECMAScript

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

Во-первых, в строгом режиме зарезервирован для использования следующий список ключевых слов: `implements`, `interface`, `let`, `package`, `private`, `protected`, `public`, `static` и `yield`. В строгом режиме, следовательно, вы не можете задействовать эти слова для именования или обращения к переменным или аргументам.

```js
function package(protected) {
  // !!!
  "use strict";
  var implements; // !!!

  // !!!
  interface: while (true) {
    break interface; // !!!
  }

  function private() {} // !!!
}
function fun(static) {
  "use strict";
} // !!!
```

Два замечания, специфичных для Mozilla: Первое, если ваш код создан на JavaScript 1.7 или выше (например, chrome code, или тег `<script type="">` заполнен правильно), и применён строгий режим, то `let` и `yield` имеют ту же функциональность, которая у них была изначально, когда они только появились. Однако в веб, в строгом коде загруженном через `<script src="">` или `<script>...</script>`, нельзя будет использовать `let`/`yield` в качестве идентификаторов. Второе, в то время как ES5 зарезервировал слова `class`, `enum`, `export`, `extends`, `import` и `super` для любого режима, в Firefox 5 Mozilla они были зарезервированы намного раньше и лишь для строгого режима.

Во-вторых, в строгом режиме запрещается объявление функций глубже самого верхнего уровня скрипта или функции. В обычном коде в браузерах, объявление функций позволено "везде", *что не является частью ES5 (или даже ES3!)* Это расширение различных браузеров, не имеющее общего совместимого подхода. Есть надежда, что в последующих редакциях ECMAScript будет определена новая семантика для объявления функций вне верхнего уровня скрипта или функции. Запрет на объявление таких функций в строгом режиме производит "зачистку" для спецификации в будущем релизе ECMAScript:

```js
"use strict";
if (true) {
  function f() {} // !!! синтаксическая ошибка
  f();
}
for (var i = 0; i < 5; i++) {
  function f2() {} // !!! синтаксическая ошибка
  f2();
}
function baz() {
  // верно
  function eit() {} // тоже верно
}
```

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

Строгий режим в браузерах
-------------------------

В большинстве браузеров в настоящее время строгий режим реализован. Однако не стоит впадать в слепую зависимость от него, потому что существует множество Версий браузеров, поддерживающих строгий режим лишь частично или вовсе не поддерживающих оный (например, Internet Explorer ниже версии 10!). *Строгий режим изменяет семантику.* Надежда на эти изменения приведёт к ошибкам и погрешностям в браузерах, в которых строгий режим не реализован. Проявляйте осторожность при использовании строгого режима, и подкрепляйте надёжность строгого режима тестами особенностей, которые проверяют, насколько верно реализованы его фрагменты. Наконец, старайтесь *тестировать свой код в браузерах, как поддерживающих, так и не поддерживающих строгий режим*. Если вы проводите тестирование только в тех браузерах, которые не поддерживают строгий режим, то вполне вероятно у вас появятся проблемы в браузерах, его поддерживающих, и наоборот.

Смотрите также
--------------

* Where's Walden? » New ES5 strict mode support: now with poison pills!
* Where's Walden? » New ES5 strict mode requirement: function statements not at top level of a program or function are prohibited
* Where's Walden? » New ES5 strict mode support: new vars created by strict mode eval code are local to that code only
* John Resig - ECMAScript 5 Strict Mode, JSON, and More
* ECMA-262-5 in detail. Chapter 2. Strict Mode.
* Strict mode compatibility table


Стандартные встроенные объекты - JavaScript

Стандартные встроенные объекты
==============================

Сводка
------

Эта глава описывает все стандартные встроенные объекты JavaScript, вместе с их методами и свойствами.

Термин «глобальные объекты» (или стандартные встроенные объекты) здесь не следует путать с самим *глобальным объектом*. Далее в главе под этим обозначением понимаются *объекты в глобальном пространстве имён* (но только, если не используется строгий режим ECMAScript 5! В противном случае они возвращают `undefined`). Сам же *глобальный объект* в глобальном пространстве имён доступен через оператор `this`. На самом деле, глобальное пространство имён *состоит из* свойств глобального объекта (в том числе включая унаследованные свойства, если они есть).

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

Стандартные объекты (по категориям)
-----------------------------------

### Значения

Глобальные свойства, возвращающие простое значение.

* `Infinity`
* `NaN`
* `undefined`
* литерал `null`
### Функции

Глобальные функции, возвращающие результат определённой подпрограммы.

* `eval()`
* `uneval()` (en-US)
Non-standard
* `isFinite()`
* `isNaN()`
* `parseFloat()`
* `parseInt()`
* `decodeURI()`
* `decodeURIComponent()`
* `encodeURI()`
* `encodeURIComponent()`
* `escape()`
Устарело
* `unescape()`
Устарело
### Фундаментальные объекты

Общие языковые объекты, функции и ошибки.

* `Object`
* `Function`
* `Boolean`
* `Symbol`
* `Error`
* `EvalError`
* `InternalError`
* `RangeError`
* `ReferenceError`
* `SyntaxError`
* `TypeError`
* `URIError`
### Числа и даты

Объекты, имеющие дело с числами, датами и математическими вычислениями.

* `Number`
* `Math`
* `Date`
### Обработка текста

Объекты для манипулирования текстом.

* `String`
* `RegExp`
### Индексированные коллекции

Коллекции, упорядоченные по индексам. Массивоподобные объекты.

* `Array`
* `Int8Array`
* `Uint8Array` (en-US)
* `Uint8ClampedArray`
* `Int16Array` (en-US)
* `Uint16Array` (en-US)
* `Int32Array`
* `Uint32Array` (en-US)
* `Float32Array`
* `Float64Array`
### Коллекции по ключу

Коллекции объектов по ключу. Элементы обходятся в порядке вставки.

* `Map` (en-US)
* `Set`
* `WeakMap`
* `WeakSet`
### Структурированные данные

Буферы данных и Объектная нотация JavaScript (**J**ava**S**cript **O**bject **N**otation).

* `ArrayBuffer` (en-US)
* `DataView` (en-US)
* `JSON`
### Объекты управляющих абстракций

* `Promise`
### Рефлексия

* `Reflect`
Экспериментальная возможность
* `Proxy`
Экспериментальная возможность
### Интернационализация

Дополнения к ядру ECMAScript, отвечающие за функциональность, чувствительную к языку.

* `Intl`
* `Intl.Collator`
* `Intl.DateTimeFormat`
* `Intl.NumberFormat`
### Нестандартные объекты

* `Generator`
Non-standard
* `Iterator` (en-US)
Non-standard
* `ParallelArray`
Non-standard
* `StopIteration`
Non-standard
### Прочее

* Аргументы функции (`arguments`)


Классы - JavaScript

Классы
======

Baseline Widely available
-------------------------

This feature is well established and works across many devices and browser versions. It’s been available across browsers since March 2017.

* Learn more
* See full compatibility
* Report feedback
Классы в JavaScript были введены в ECMAScript 2015 и представляют собой синтаксический сахар над существующим в JavaScript механизмом прототипного наследования. Синтаксис классов **не вводит** новую объектно-ориентированную модель, а предоставляет более простой и понятный способ создания объектов и организации наследования.

Определение классов
-------------------

На самом деле классы — это "специальные функции", поэтому точно также, как вы определяете функции (function expressions и function declarations), вы можете определять и классы с помощью: class declarations и class expressions.

### Объявление класса

Первый способ определения класса — **class declaration (*объявление класса*)**. Для этого необходимо воспользоваться ключевым словом `class` и указать имя класса (в примере — «Rectangle»).

```js
class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}
```

#### Подъём (hoisting)

Разница между *объявлением функции* (*function declaration*) и *объявлением класса* (*class declaration*) в том, что *объявление функции* совершает подъём (hoisting), в то время как *объявление класса* — нет. Поэтому вначале необходимо объявить ваш класс и только затем работать с ним, а код же вроде следующего сгенерирует исключение типа `ReferenceError`:

```js
var p = new Rectangle(); // ReferenceError

class Rectangle {}
```

### Выражение класса

Второй способ определения класса — **class expression (*выражение класса*)**. Можно создавать именованные и безымянные выражения. В первом случае имя выражения класса находится в локальной области видимости класса и может быть получено через свойства самого класса, а не его экземпляра.

```js
// безымянный
var Rectangle = class {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};
console.log(Rectangle.name);
// отобразится: "Rectangle"

// именованный
var Rectangle = class Rectangle2 {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};
console.log(Rectangle.name);
// отобразится: "Rectangle2"
```

**Примечание:** выражения класса подвержены тем же проблемам с подъёмом (hoisting), что и **объявления** класса.

Тело класса и задание методов
-----------------------------

Тело класса — это часть кода, заключённая в фигурные скобки `{}`. Здесь вы можете объявлять члены класса, такие как методы и конструктор.

### Строгий режим

Тела *объявлений классов* и *выражений классов* выполняются в строгом режиме (strict mode).

### Constructor

Метод `constructor` — специальный метод, необходимый для создания и инициализации объектов, созданных, с помощью класса. В классе может быть только один метод с именем `constructor`. Исключение типа `SyntaxError` будет выброшено, если класс содержит более одного вхождения метода `constructor`.

Ключевое слово `super` можно использовать в методе `constructor` для вызова конструктора родительского класса.

### Методы прототипа

Смотрите также определение методов.

```js
class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }

  get area() {
    return this.calcArea();
  }

  calcArea() {
    return this.height \* this.width;
  }
}

const square = new Rectangle(10, 10);

console.log(square.area); // 100
```

### Статические методы и свойства

Ключевое слово `static`, определяет статический метод или свойства для класса. Статические методы и свойства вызываются без инстанцирования (en-US) их класса, и **не могут** быть вызваны у экземпляров (*instance*) класса. Статические методы, часто используются для создания служебных функций для приложения, в то время как статические свойства полезны для кеширования в рамках класса, фиксированной конфигурации или любых других целей, не связанных с реплецированием данных между экземплярами.

```js
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  static displayName = "Точка";
  static distance(a, b) {
    const dx = a.x - b.x;
    const dy = a.y - b.y;

    return Math.hypot(dx, dy);
  }
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);
p1.displayName; //undefined
p1.distance; //undefined
p2.displayName; //undefined
p2.distance; //undefined

console.log(Point.displayName); // "Точка"
console.log(Point.distance(p1, p2)); // 7.0710678118654755
```

### Привязка `this` в прототипных и статических методах

Когда статический или прототипный метод вызывается без привязки к this объекта (или когда this является типом boolean, string, number, undefined, null), тогда this будет иметь значение undefined внутри вызываемой функции. Поведение будет таким же даже без директивы `"use strict"`, потому что код внутри тела класса всегда выполняется в строгом режиме.

```js
class Animal {
  speak() {
    return this;
  }
  static eat() {
    return this;
  }
}

let obj = new Animal();
obj.speak(); // объект Animal
let speak = obj.speak;
speak(); // undefined

Animal.eat(); // класс Animal
let eat = Animal.eat;
eat(); // undefined
```

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

```js
function Animal() {}

Animal.prototype.speak = function () {
  return this;
};

Animal.eat = function () {
  return this;
};

let obj = new Animal();
let speak = obj.speak;
speak(); // глобальный объект (нестрогий режим)

let eat = Animal.eat;
eat(); // глобальный объект (нестрогий режим)
```

### Свойства экземпляра

Свойства экземпляра должны быть определены в методе класса:
```

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}
```

Статические (class-side) свойства и свойства прототипа должны быть определены за рамками тела класса:
```

Rectangle.staticWidth = 20;
Rectangle.prototype.prototypeWidth = 25;
```

### Определение полей

**Предупреждение:** Публичные и приватные поля - это экспериментальная особенность (stage 3), предложенная комитетом TC39 по стандартам языка Javascript. Поддержка браузерами ограничена, но это нововведение может быть использовано на моменте сборки, используя к примеру Babel.

#### Публичные поля

Используя Javascript синтаксис определения полей, приведённый выше пример может быть изменён следующим образом:
```

class Rectangle {
  height = 0;
  width;
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}
```

Как видно из примера, поля могут быть объявлены как со начальным значением, так и без него.

Более подробно об этом написано в публичные поля класса.

#### Приватные поля

Предыдущий пример может быть изменён следующим образом, используя приватные поля:
```

class Rectangle {
  #height = 0;
  #width;
  constructor(height, width) {
    this.#height = height;
    this.#width = width;
  }
}
```

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

**Примечание:** Приватные поля могут быть объявлены только заранее в объявлении поля.

Приватные поля не могут быть созданы позже путём присваивания им значения, в отличии от обычных свойств.

Более подробно об этом написано в Приватные поля класса.

Наследование классов с помощью `extends`
----------------------------------------

Ключевое слово `extends` используется в *объявлениях классов* и *выражениях классов* для создания класса, дочернего относительно другого класса.

```js
class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} издаёт звук.`);
  }
}

class Dog extends Animal {
  constructor(name) {
    super(name); // вызывает конструктор super класса и передаёт параметр name
  }

  speak() {
    console.log(`${this.name} лает.`);
  }
}

let d = new Dog("Митци");
d.speak(); // Митци лает
```

Если в подклассе присутствует конструктор, он должен сначала вызвать super, прежде чем использовать this.

Аналогичным образом можно расширять традиционные, основанные на функциях "классы":

```js
function Animal(name) {
  this.name = name;
}
Animal.prototype.speak = function () {
  console.log(`${this.name} издаёт звук.`);
};

class Dog extends Animal {
  speak() {
    console.log(`${this.name} лает.`);
  }
}

let d = new Dog("Митци");
d.speak(); // Митци лает

// Для аналогичных методов дочерний метод имеет приоритет над родительским.
```

Обратите внимание, что классы не могут расширять обычные (non-constructible) объекты. Если вам необходимо создать наследование от обычного объекта, в качестве замены можно использовать `Object.setPrototypeOf()`:

```js
var Animal = {
  speak() {
    console.log(`${this.name} издаёт звук.`);
  },
};

class Dog {
  constructor(name) {
    this.name = name;
  }
}

// Если вы этого не сделаете, вы получите ошибку TypeError при вызове speak.
Object.setPrototypeOf(Dog.prototype, Animal);

let d = new Dog("Митци");
d.speak(); // Митци издаёт звук.
```

Species
-------

Допустим, вам хотелось бы возвращать объекты типа `Array` в вашем производном от массива классе `MyArray`. Паттерн species позволяет вам переопределять конструкторы по умолчанию.

Например, при использовании таких методов, как `map()`, который возвращает конструктор по умолчанию, вам хотелось бы, чтобы они возвращали родительский объект `Array` вместо объекта `MyArray`. Символ `Symbol.species` позволяет это реализовать:

```js
class MyArray extends Array {
  // Изменить species на родительский конструктор Array
  static get [Symbol.species]() {
    return Array;
  }
}
var a = new MyArray(1, 2, 3);
var mapped = a.map((x) => x \* x);

console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array); // true
```

Обращение к родительскому классу с помощью `super`
--------------------------------------------------

Ключевое слово `super` используется для вызова функций на родителе объекта.

```js
class Cat {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} издаёт звук.`);
  }
}

class Lion extends Cat {
  speak() {
    super.speak();
    console.log(`${this.name} рычит.`);
  }
}

let l = new Lion("Фаззи");
l.speak();
// Фаззи издаёт звук.
// Фаззи рычит.
```

Mix-ins
-------

Абстрактные подклассы, или mix-ins, — это шаблоны для классов. У класса в ECMAScript может быть только один родительский класс, поэтому множественное наследование (к примеру, от tooling classes) невозможно. Функциональность должен предоставлять родительский класс.

Для реализации mix-ins в ECMAScript можно использовать функцию, которая в качестве аргумента принимает родительский класс, а возвращает подкласс, его расширяющий:

```js
var calculatorMixin = (Base) =>
  class extends Base {
    calc() {}
  };

var randomizerMixin = (Base) =>
  class extends Base {
    randomize() {}
  };
```

Класс, использующий такие mix-ins, можно описать следующим образом:

```js
class Foo {}
class Bar extends calculatorMixin(randomizerMixin(Foo)) {}
```

Спецификации
------------

| Specification |
| --- |
| ECMAScript Language Specification # sec-class-definitions |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Повторное определение класа
---------------------------

Класс не может быть переопределён. Попытка этого приведёт к `SyntaxError` .

Если мы запускаете код в веб браузере, к примеру в Firefox Web Console (**Tools** > **Web Developer** > **Web Console**) и вы используете ('Run') определение класса с одним и тем же именем дважды, вы получите `SyntaxError: redeclaration of let ClassName;`. (Обсуждение по ошибке можно посмотреть в Firefox bug 1428672.) Chrome Developer Tools возвращает сообщение типа `Uncaught SyntaxError: Identifier 'ClassName' has already been declared at <anonymous>:1:1`.

Смотрите также
--------------

* Функции
* Определение классов
* Выражение классов
* Публичные поля класса
* Приватные поля класса
* super
* Статья в блоге: "ES6 In Depth: Classes"
* Fields and public/private class properties proposal (stage 3)


Deprecated and obsolete features - JavaScript

Deprecated and obsolete features
================================

This page lists features of JavaScript that are deprecated (that is, still available but planned for removal) and obsolete (that is, no longer usable).

Deprecated features
-------------------

These deprecated features can still be used, but should be used with caution because they are expected to be removed entirely sometime in the future. You should work to remove their use from your code.

### RegExp properties

The following properties are deprecated. This does not affect their use in replacement strings:

| Свойство | Описание |
| --- | --- |
| `$1-$9` | Parenthesized substring matches, if any. **Warning:** Using these properties can result in problems, since browser extensions can modify them. Avoid them! |
| `$_` | Смотрите `input`. |
| `$*` | Смотрите `multiline`. |
| `$&` | Смотрите `lastMatch`. |
| `$+` (en-US) | Смотрите `lastParen`. |
| `$`` (en-US) | Смотрите `leftContext`. |
| `$'` (en-US) | Смотрите `rightContext`. |
| `input` | The string against which a regular expression is matched. |
| `lastMatch` | The last matched characters. |
| `lastParen` (en-US) | The last parenthesized substring match, if any. |
| `leftContext` (en-US) | The substring preceding the most recent match. |
| `rightContext` (en-US) | The substring following the most recent match. |

The following are now properties of `RegExp` instances, no longer of the `RegExp` object:

| Свойство | Описание |
| --- | --- |
| `global` | Whether or not to test the regular expression against all possible matches in a string, or only against the first. |
| `ignoreCase` | Whether or not to ignore case while attempting a match in a string. |
| `lastIndex` | The index at which to start the next match. |
| `multiline` | Whether or not to search in strings across multiple lines. |
| `source` | The text of the pattern. |

### RegExp methods

* The `compile()` (en-US) method is deprecated.
* The `valueOf` method is no longer specialized for `RegExp`. Use `Object.valueOf()`.
### Function properties

* The `caller` and `arguments` properties are deprecated, because they leak the function caller. Instead of the arguments property, you should use the `arguments` object inside function closures.
### Legacy generator

* `Legacy generator function statement` (en-US) and `Legacy generator function expression` (en-US) are deprecated. Use `function* statement` and `function* expression` instead.
* `JS1.7/JS1.8 Array comprehension` (en-US) and `JS1.7/JS1.8 Generator comprehension` (en-US) are deprecated.
### Iterator

* `StopIteration` устарел.
* `Iterator` (en-US) устарел.
### Object methods

* `watch` and `unwatch` are deprecated. Use `Proxy` instead.
* `__iterator__` устарел.
* `Object.prototype.__noSuchMethod__` is deprecated. Use `Proxy` instead.
### Методы даты

* `getYear` и `setYear` are affected by the Year-2000-Problem and have been subsumed by `getFullYear` и `setFullYear`.
* You should use `toISOString` instead of the deprecated `toGMTString` (en-US) method in new code.
* `toLocaleFormat` is deprecated.
### Functions

* Expression closures are deprecated. Use regular `functions` or arrow functions instead.
### Proxy

* Proxy.create and Proxy.createFunction are deprecated. Use `Proxy` instead.
* The following traps are obsolete:
    + `hasOwn` (Firefox bug 980565, Firefox 33).
    + `getEnumerablePropertyKeys` (Firefox bug 783829, Firefox 37)
    + `getOwnPropertyNames` (Firefox bug 1007334, Firefox 33)
    + `keys` (Firefox bug 1007334, Firefox 33)
### Escape sequences

* Octal escape sequences (\ followed by one, two, or three octal digits) are deprecated in string and regular expression literals.
* The `escape` and `unescape` functions are deprecated. Use `encodeURI`, `encodeURIComponent`, `decodeURI` or `decodeURIComponent` to encode and decode escape sequences for special characters.
### Методы строк

* HTML wrapper methods like `String.prototype.fontsize` and `String.prototype.big`.
* `String.prototype.quote` is removed from Firefox 37.
* non standard `flags` parameter in `String.prototype.search`, `String.prototype.match`, and `String.prototype.replace` are deprecated.
* `String.prototype.substr` probably won't be removed anytime soon, but it's defined in Annex B of the ECMA-262 standard, whose introduction states: "… Programmers should not use or assume the existence of these features and behaviours when writing new ECMAScript code. …"
Obsolete features
-----------------

These obsolete features have been entirely removed from JavaScript and can no longer be used as of the indicated version of JavaScript.

### Объект

| Свойство | Описание |
| --- | --- |
| `**count**` | Returns the number of enumerable properties directly on a user-defined object. |
| `**parent**` | Points to an object's context. |
| `Object.prototype.eval()` | Evaluates a string of JavaScript code in the context of the specified object. |
| `Object.observe()` | Asynchronously observing the changes to an object. |
| `Object.unobserve()` | Remove observers. |
| `Object.getNotifier()` | Creates an object that allows to synthetically trigger a change. |

### Function

| Свойство | Описание |
| --- | --- |
| `arity` | Number of formal arguments. |

### Массив

| Свойство | Описание |
| --- | --- |
| `Array.observe()` | Асинхронный просмотр изменений в массивах. |
| `Array.unobserve()` | Remove observers. |

### Число

* `Number.toInteger()`
### ParallelArray

* `ParallelArray`
### Statements

* `for each...in` is deprecated. Use `for...of` instead.
* Destructuring `for...in` is deprecated. Use `for...of` instead.
* let blocks and let expressions are obsolete.
### E4X

Смотрите E4X.

### Sharp variables

Смотрите Sharp variables in JavaScript.


JavaScript ссылки на ошибки - JavaScript

JavaScript ссылки на ошибки
===========================

Ниже, вы найдёте список ошибок, которые возвращает JavaScript. Эти ошибки могут быть полезны при отладке, но неполадки не всегда сразу понятны. Страницы ниже предлагают дополнительную информацию об этих ошибках. Каждая ошибка это Объект на основании `Error` object, и имеет имя (`name)` и сообщение (`message)`.

Ошибки отображённые в Web консоли могут содержать ссылку на соответствующую страницу ниже, чтобы помочь вам быстро понять проблему в коде.

Список ошибок
-------------

В представленном списке, каждая страница переименована (тип ошибки) и сообщение (более подробное удобочитаемое сообщение об ошибке). Вместе, эти два свойства послужат отправной точкой к пониманию и устранению ошибки. Для большей информации, перейдите по ссылкам ниже!

* Error: Permission denied to access property "x"
* InternalError: too much recursion
* RangeError: argument is not a valid code point
* RangeError: invalid array length
* RangeError: invalid date
* RangeError: precision is out of range
* RangeError: radix must be an integer
* RangeError: repeat count must be less than infinity
* RangeError: repeat count must be non-negative
* ReferenceError: "x" is not defined
* ReferenceError: assignment to undeclared variable "x"
* ReferenceError: can't access lexical declaration 'X' before initialization
* ReferenceError: invalid assignment left-hand side
* ReferenceError: reference to undefined property "x"
* SyntaxError: "0"-prefixed octal literals and octal escape seq. are deprecated
* SyntaxError: "use strict" not allowed in function with non-simple parameters
* SyntaxError: "x" is a reserved identifier
* SyntaxError: JSON.parse: bad parsing
* SyntaxError: Unexpected token
* SyntaxError: Using //@ to indicate sourceURL pragmas is deprecated. Use //# instead
* SyntaxError: a declaration in the head of a for-of loop can't have an initializer
* SyntaxError: applying the 'delete' operator to an unqualified name is deprecated
* SyntaxError: for-in loop head declarations may not have initializers
* SyntaxError: function statement requires a name(функция оператор требует имя)
* SyntaxError: identifier starts immediately after numeric literal
* SyntaxError: illegal character
* SyntaxError: invalid regular expression flag "x"
* SyntaxError: missing ) after condition
* SyntaxError: missing : after property id
* SyntaxError: missing ; before statement
* SyntaxError: missing = in const declaration
* SyntaxError: missing ] after element list
* SyntaxError: missing formal parameter( отсутствует формальный параметр)
* SyntaxError: missing name after . operator(отсутствует имя после. оператора)
* SyntaxError: missing variable name
* SyntaxError: missing } after function body
* SyntaxError: missing } after property list
* SyntaxError: redeclaration of formal parameter "x"
* SyntaxError: return not in function
* SyntaxError: test for equality (==) mistyped as assignment (=)?(тест на равенство (==) опечатка как присваивание (=)?)
* SyntaxError: unterminated string literal
* TypeError: "x" has no properties
* TypeError: "x" is (not) "y"
* TypeError: "x" is not a constructor
* TypeError: "x" is not a function
* TypeError: "x" is not a non-null object(Тип ошибки: "x" не является ненулевым объектом)
* TypeError: "x" is read-only(Ошибка Типа: "x" только для чтения)
* TypeError: 'x' is not iterable (Тип ошибки 'x' не является итерационным)
* TypeError: More arguments needed
* TypeError: Reduce of empty array with no initial value(Тип ошибки: уменьшение пустого массива без начального значения)
* TypeError: can't assign to property "x" on "y": not an object
* TypeError: can't define property "x": "obj" is not extensible
* TypeError: can't delete non-configurable array element(Тип ошибки:не удаётся удалить настраиваемый элемент массива)
* TypeError: can't redefine non-configurable property "x"
* TypeError: cannot use 'in' operator to search for 'x' in 'y'(не удаётся использовать 'in' оператор поиска для 'x' в 'y')
* TypeError: cyclic object value
* TypeError: invalid 'instanceof' operand 'x'(Тип ошибки: неверный 'экземпляром' операнд 'х')
* TypeError: invalid Array.prototype.sort argument (TypeError: недопустимый Array.prototype.sort argument)
* TypeError: invalid assignment to const "x"(недопустимое назначение const "x")
* TypeError: property "x" is non-configurable and can't be deleted(свойство "x" не настраивается и не может быть удалено)
* TypeError: setting getter-only property "x"(установка свойства только для геттера "x")
* URIError: malformed URI sequence
* Warning: -file- is being assigned a //# sourceMappingURL, but already has one
* Warning: unreachable code after return statement
* X.prototype.y called on incompatible type
* Ошибка Ссылки: устаревший вызывающий объект или использование аргументов
* Синтаксическая ошибка: пропущенный символ ")" после списка аргументов
Смотрите также
--------------

* What went wrong? Troubleshooting JavaScript: Вводный Учебник для начинающих для исправления ошибок JavaScript.


Шаблонные строки - JavaScript

Шаблонные строки
================

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

Синтаксис
---------
```

`строка текста`

`строка текста 1
 строка текста 2`

`строка текста ${выражение} строка текста`

tag `строка текста ${выражение} строка текста`
```

Описание
--------

Шаблонные литералы заключены в обратные кавычки (` `) вместо двойных или одинарных. Они могут содержать подстановки, обозначаемые знаком доллара и фигурными скобками (`${выражение}`). Выражения в подстановках и текст между ними передаются в функцию. По умолчанию функция просто объединяет все части в строку. Если перед строкой есть выражение (здесь это `tag`), то шаблонная строка называется "теговым шаблоном". В этом случае, теговое выражение (обычно функция) вызывается с обработанным шаблонным литералом, который вы можете изменить перед выводом. Для экранирования обратной кавычки в шаблонных литералах указывается обратный слеш **\**.

```js
`\`` === "`"; // --> true
```

### Многострочные литералы

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

```js
console.log("string text line 1\n" + "string text line 2");
// "string text line 1
// string text line 2"
```

То же с использованием шаблонных литералов:

```js
console.log(`string text line 1
string text line 2`);
// "string text line 1
// string text line 2"
```

### Интерполяция выражений

Для вставки выражений в обычные строки вам пришлось бы использовать следующий синтаксис:

```js
var a = 5;
var b = 10;
console.log("Fifteen is " + (a + b) + " and not " + (2 \* a + b) + ".");
// "Fifteen is 15 and not 20."
```

Теперь, при помощи шаблонных литералов, вам доступен "синтаксический сахар", делающий подстановки вроде той более читабельными:

```js
var a = 5;
var b = 10;
console.log(`Fifteen is ${a + b} and not ${2 \* a + b}.`);
// "Fifteen is 15 and not 20."
```

### Вложенные шаблоны

Временами, вложить шаблон — это кратчайший и, возможно, более читабельный способ составить строку. Просто поместите внутрь шаблона с обратными кавычками ещё одни, обернув их в подстановку `${ }`. Например, если выражение истинно, можно вернуть шаблонный литерал.

В ES5:

```js
var classes = "header";
classes += isLargeScreen()
  ? ""
  : item.isCollapsed
    ? " icon-expander"
    : " icon-collapser";
```

В ES2015 с шаблонными литералами без вложения:

```js
const classes = `header ${
 isLargeScreen() ? "" : item.isCollapsed ? "icon-expander" : "icon-collapser"
}`;
```

В ES2015 с вложенными шаблонными литералами:

```js
const classes = `header ${
 isLargeScreen() ? "" : `icon-${item.isCollapsed ? "expander" : "collapser"}`
}`;
```

### Теговые шаблоны

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

```js
var person = "Mike";
var age = 28;

function myTag(strings, personExp, ageExp) {
  var str0 = strings[0]; // "That "
  var str1 = strings[1]; // " is a "

  // Технически, в конце итогового выражения
  // (в нашем примере) есть ещё одна строка,
  // но она пустая (""), так что пропустим её.
  // var str2 = strings[2];

  var ageStr;
  if (ageExp > 99) {
    ageStr = "centenarian";
  } else {
    ageStr = "youngster";
  }

  // Мы даже можем вернуть строку, построенную другим шаблонным литералом
  return `${str0}${personExp}${str1}${ageStr}`;
}

var output = myTag`That ${person} is a ${age}`;

console.log(output);
// That Mike is a youngster
```

Функция тега не обязана возвращать строку, как показано в примере ниже:

```js
function template(strings, ...keys) {
  return function (...values) {
    var dict = values[values.length - 1] || {};
    var result = [strings[0]];
    keys.forEach(function (key, i) {
      var value = Number.isInteger(key) ? values[key] : dict[key];
      result.push(value, strings[i + 1]);
    });
    return result.join("");
  };
}

var t1Closure = template`${0}${1}${0}!`;
t1Closure("Y", "A"); // "YAY!"
var t2Closure = template`${0} ${"foo"}!`;
t2Closure("Hello", { foo: "World" }); // "Hello World!"
```

### Сырые строки

Специальное свойство `raw`, доступное для первого аргумента тегового шаблона, позволяет получить строку в том виде, в каком она была введена, без экранирования.

```js
function tag(strings) {
  return strings.raw[0];
}

tag`string text line 1 \\n string text line 2`;
// выводит "string text line 1 \\n string text line 2",
// включая 'n' и два символа '\'
```

Вдобавок, существует метод `String.raw()`, возвращающий точно такую же исходную строку, какую вернула бы функция шаблона по умолчанию и строковая конкатенация вместе.

```js
var str = String.raw`Hi\n${2 + 3}!`;
// "Hi\n5!"

str.length;
// 6

str.split("").join(",");
// "H,i,\,n,5,!"
```

### Теговые шаблоны и экранирование символов

#### Поведение в ES2016

В ECMAScript 2016 теговые шаблоны следуют правилам экранирования следующих символов:

* символы Unicode, начинающиеся с "\u", например, `\u00A9`
* точки кода Unicode, начинающиеся с "\u{}", например, `\u{2F804}`
* шестнадцатеричные представления символов, начинающиеся с "\x", например, `\xA9`
* восьмеричные представления символов, начинающиеся с "\", например, `\251`

Отсюда вытекает проблема теговых шаблонов: следуя грамматике ECMAScript, анализатор кода, найдя символ `\`, будет искать корректное представление символа Unicode, но может не найти его вовсе. Пример ниже показывает это:

```js
latex`\unicode`;
// В старых версиях ECMAScript (ES2016 и раньше) выкинет исключение:
// SyntaxError: malformed Unicode character escape sequence
```

#### Поведение в ES2018

Теговые шаблоны должны позволять встраивать языки (например, DSLs или LaTeX), в которых широко используются многие другие экранирования. Предложение Редакция шаблонных литералов (уровень 4, одобренный к добавлению в стандарт ECMAScript 2018) устраняет синтаксические ограничения экранирования теговых шаблонов в ECMAScript.

Однако, некорректное экранирование символов по-прежнему нужно отображать в "приготовленном" отображении. Оно показывается в виде `undefined` в "приготовленном" массиве:

```js
function latex(str) {
  return { cooked: str[0], raw: str.raw[0] };
}

latex`\unicode`;

// { cooked: undefined, raw: "\unicode" }
```

Заметьте, что ограничение на экранирование символов проявляется лишь в *теговых* шаблонах, и не проявляется в *нетеговых* шаблонных литералах:

```js
let bad = `bad escape sequence: \unicode`;
```

Спецификации
------------

| Specification |
| --- |
| ECMAScript Language Specification # sec-template-literals |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Смотрите также
--------------

* `String`
* `String.raw()`
* Лексическая грамматика
* Подобные шаблонам строки в ES3-совместимом синтаксисе
* ES6 в деталях: шаблонные строки


The Iterator protocol - JavaScript

The Iterator protocol
=====================

Одно из нововведений стандарта ECMAScript 2015 - протоколы перебора, которые могут реализованы любым объектом, соблюдая при этом определённые правила.

Протоколы перебора
------------------

Протоколы перебора включают the "iterable" protocol и the "iterator" protocol.

### Протокол "Итерируемый"

Протокол "**Итерируемый**" позволяет JavaScript объектам определять или настраивать поведение перебора, например, то какие значения перебираются в конструкции `for..of`. Некоторые встроенные типы, такие как `Array` или `Map` (en-US), имеют поведение перебора по умолчанию, в то время как другие типы (такие как `Object`) его не имеют

Для того, чтобы объект был **итерируемым**, в нем должен быть реализован метод **@@iterator**, т.е. этот объект (или любой из объектов из его prototype chain) должен иметь свойство с именем `Symbol``.iterator`:

| Свойство | Значение |
| --- | --- |
| `[Symbol.iterator]` | Функция без аргументов, возвращающая объект, соответствующий iterator protocol. |

Всякий раз, когда объект подлежит перебору (например, когда в коде встречается цикл `for..of`), вызывается его метод `@@iterator` без аргументов, и возвращаемый **iterator** используется для получения перебираемых значений.

### Протокол "Итератор"

Протокол "**Итератор**" определяет стандартный способ получения последовательности значений (конечной или бесконечной).

Объект является итератором, если в нем определён метод **next()** , реализующий следующую логику:

| Свойство | Значение |
| --- | --- |
| `next` | Функция без аргументов, возвращающая объект с двумя свойствами:* `done` (boolean)
    + Принимает значение `true` если итератор достиг конца
     итерируемой последовательности. В этом случае свойство
     `value` может определять
     *возвращаемое значение* итератора. Возвращаемые значения
     объясняются более подробно
     here.
    + Принимает значение `false` если итератор может
     генерировать следующее значение последовательности. Это
     эквивалентно не указанному done.
* `value` - любое JavaScript значение, возвращаемое
 итератором. Может быть опущено, если
 `done имеет значение` `true`.
 |

Некоторые итераторы, в свою очередь, итерабельны:

```js
var someArray = [1, 5, 7];
var someArrayEntries = someArray.entries();

someArrayEntries.toString(); // "[object Array Iterator]"
someArrayEntries === someArrayEntries[Symbol.iterator](); // true
```

Примеры использования протокола "итератора"
-------------------------------------------

`String` является примером встроенного итерабельного объекта:

```js
var someString = "hi";
typeof someString[Symbol.iterator]; // "function"
```

По умолчанию итератор строки возвращает символы строки друг за другом:

```js
var iterator = someString[Symbol.iterator]();
iterator + ""; // "[object String Iterator]"

iterator.next(); // { value: "h", done: false }
iterator.next(); // { value: "i", done: false }
iterator.next(); // { value: undefined, done: true }
```

Некоторые встроенные конструкции языка, например, spread operator, используют в своей внутренней реализации тот же протокол итерации:

```js
[...someString]; // ["h", "i"]
```

Поведение итератора можно переопределить применив собственный `@@iterator`:

```js
var someString = new String("hi"); // need to construct a String object explicitly to avoid auto-boxing

someString[Symbol.iterator] = function () {
  return {
    // this is the iterator object, returning a single element, the string "bye"
    next: function () {
      if (this._first) {
        this._first = false;
        return { value: "bye", done: false };
      } else {
        return { done: true };
      }
    },
    \_first: true,
  };
};
```

Notice how redefining `@@iterator` affects the behavior of built-in constructs, that use the iteration protocol:

```js
[...someString]; // ["bye"]
someString + ""; // "hi"
```

Встроенная итерируемость
------------------------

`String`, `Array`, `TypedArray`, `Map` (en-US) и `Set` итерируемы, так как их прототипы содержат `@@iterator` метод, а `Object` нет, так как прототип `Object` не содержит метода `@@iterator`

Итерируемость определённая пользователем
----------------------------------------

Мы можем создать итерируемый объект сами:

```js
var myIterable = {};
myIterable[Symbol.iterator] = function\* () {
  yield 1;
  yield 2;
  yield 3;
};
[...myIterable]; // [1, 2, 3]
```

Builtin APIs need iterables
---------------------------

`Map([iterable])` (en-US), `WeakMap([iterable])`, `Set([iterable])` and `WeakSet([iterable])`:

```js
var myObj = {};
new Map([
  [1, "a"],
  [2, "b"],
  [3, "c"],
]).get(2); // "b"
new WeakMap([
  [{}, "a"],
  [myObj, "b"],
  [{}, "c"],
]).get(myObj); // "b"
new Set([1, 2, 3]).has(3); // true
new Set("123").has("2"); // true
new WeakSet(
  (function\* () {
    yield {};
    yield myObj;
    yield {};
  })(),
).has(myObj); // true
```

and `Promise.all(iterable)`, `Promise.race(iterable)`, `Array.from()`

Синтаксис предполагающий итерируемость
--------------------------------------

for-of, spread, yield\*, destructing - использование данного синтаксиса возможно только если типы данных, к которым он применяется, итерируемы:

```js
for (let value of ["a", "b", "c"]) {
  console.log(value);
}
// "a"
// "b"
// "c"

[..."abc"]; // ["a", "b", "c"]

function\* gen() {
  yield\* ["a", "b", "c"];
}

gen().next()[(a, b, c)] = // { value:"a", done:false }
  new Set(["a", "b", "c"]);
a; // "a"
```

Non-well-formed iterables
-------------------------

If an iterable's `@@iterator` method doesn't return an iterator object, then it's a non-well-formed iterable, using it as such is likely to result in runtime exceptions or buggy behavior:

```js
var nonWellFormedIterable = {}
nonWellFormedIterable[Symbol.iterator] = () => 1
[...nonWellFormedIterable] // TypeError: [] is not a function
```

Объект-генератор является итератором или итерируемым
----------------------------------------------------

И тем и другим

```js
var aGeneratorObject = function\*(){
    yield 1;
    yield 2;
    yield 3;
}()
typeof aGeneratorObject.next
// "function", because it has a next method, so it's an iterator
typeof aGeneratorObject[Symbol.iterator]
// "function", because it has an @@iterator method, so it's an iterable
aGeneratorObject[Symbol.iterator]() === aGeneratorObject
// true, because its @@iterator method return its self (an iterator), so it's an well-formed iterable
[...aGeneratorObject]
// [1, 2, 3]
```

Примеры
-------

### Простой итератор

```js
function makeIterator(array) {
  var nextIndex = 0;

  return {
    next: function () {
      return nextIndex < array.length
        ? { value: array[nextIndex++], done: false }
        : { done: true };
    },
  };
}

var it = makeIterator(["yo", "ya"]);

console.log(it.next().value); // 'yo'
console.log(it.next().value); // 'ya'
console.log(it.next().done); // true
```

### Бесконечный итератор

```js
function idMaker() {
  var index = 0;

  return {
    next: function () {
      return { value: index++, done: false };
    },
  };
}

var it = idMaker();

console.log(it.next().value); // '0'
console.log(it.next().value); // '1'
console.log(it.next().value); // '2'
// ...
```

### С генератором

```js
function\* makeSimpleGenerator(array) {
  var nextIndex = 0;

  while (nextIndex < array.length) {
    yield array[nextIndex++];
  }
}

var gen = makeSimpleGenerator(["yo", "ya"]);

console.log(gen.next().value); // 'yo'
console.log(gen.next().value); // 'ya'
console.log(gen.next().done); // true

function\* idMaker() {
  var index = 0;
  while (true) yield index++;
}

var gen = idMaker();

console.log(gen.next().value); // '0'
console.log(gen.next().value); // '1'
console.log(gen.next().value); // '2'
// ...
```

Спецификация
------------

| Specification |
| --- |
| ECMAScript Language Specification # sec-iteration |

Смотрите также
--------------

* Дополнительную информацию о генераторах ES 2015 смотри на отдельной странице.


Лексический синтаксис - JavaScript

Лексический синтаксис
=====================

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

ECMAScript также определяет ключевые слова и литералы и имеет указания для автоматической вставки точек с запятой к концу инструкции.

Спецсимволы
-----------

Спецсимволы не имеют визуального представления, однако используются для управления интерпретацией текста.

| Code point | Name | Abbreviation | Description |
| --- | --- | --- | --- |
| `U+200C` | Zero width non-joiner | <ZWNJ> | Размещается между символами во избежание их соединений в лигатуры для некоторых языков (Wikipedia) |
| `U+200D` | Zero width joiner | <ZWJ> | Размещается между символами, которые не могли бы нормально объединиться для того, чтобы символы отрисовывались, используя их соединительную форму в некоторых языках (Wikipedia) |
| `U+FEFF` | Byte order mark | <BOM> | Используется вначале скрипта для того, чтобы пометить Юникод и порядок байтов (Wikipedia) |

Пробелы
-------

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

| Code point | Name | Abbreviation | Description | Escape sequence |
| --- | --- | --- | --- | --- |
| U+0009 | Character tabulation | <HT> | Горизонтальная табуляция | \t |
| U+000B | Line tabulation | <VT> | Вертикальная табуляция | \v |
| U+000C | Form feed | <FF> | Символ контроля разрыва страницы (Wikipedia) | \f |
| U+0020 | Space | <SP> | Обычный пробел |  |
| U+00A0 | No-break space | <NBSP> | Обычный пробел без точки, на которой может произойти разрыв страницы |  |
| Others | Other Unicode space characters | <USP> | Другие символы в Юникоде на Википедии |  |

Окончание строк
---------------

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

Окончания строк также затрагивают процесс автоматического проставления точки с запятой. Также окончания строк попадают под условия регулярных выражений при поиске **\s** класса.

В ECMAScript, в качестве окончания строк можно использовать только ниже перечисленные Юникод символы. Другие символы окончания строк будут интерпретированы, как пробельные символы (например, Next Line, NEL, U+0085 будут интерпретироваться, как пробельные символы).

| Code point | Name | Abbreviation | Description | Escape sequence |
| --- | --- | --- | --- | --- |
| U+000A | Line Feed | <LF> | Новая строка в UNIX системах. | \n |
| U+000D | Carriage Return | <CR> | Новая строка в Commodore и ранних Mac systems. | \r |
| U+2028 | Line Separator | <LS> | Wikipedia |  |
| U+2029 | Paragraph Separator | <PS> | Wikipedia |  |

Комментарии
-----------

Комментарии используются для добавления подсказок, заметок, предложений или предупреждений. Они могут упростить чтение и понимание кода. Также они могут быть использованы для предотвращения выполнения кода (этот приём практикуется при отладке кода).

В JavaScript есть несколько способов указать комментарии в коде.

Первый способ `//` комментарий; в этом случае весь текст в строке после двойного слеша будет комментарием, например:

```js
function comment() {
  // Это комментарий в строке
  console.log("Hello world!");
}
comment();
```

Второй способ - это `/* */`, такой способ более гибок, чем первый.

Например, вы можете использовать его в одной строке:

```js
function comment() {
  /\* Это однострочный комментарий \*/
  console.log("Hello world!");
}
comment();
```

Либо вы можете сделать многострочный комментарий, как показано здесь:

```js
function comment() {
  /\* Этот комментарий располагается на нескольких линиях.
 Обратите внимание, что вам не нужно обрывать комментарий, пока вы его не закончите\*/
  console.log("Hello world!");
}
comment();
```

Также, если пожелаете, то вы можете использовать такое комментирование посреди строки кода. Хотя это может ухудшить читабельность кода:

```js
function comment(x) {
  console.log("Hello " + x /\* вставьте значение x \*/ + " !");
}
comment("world");
```

Чтобы отключить выполнение кода, просто оберните код в комментарий, как здесь:

```js
function comment() {
  /\* console.log("Hello world!"); \*/
}
comment();
```

В этом случае `console.log()` никогда не выполнится, пока он внутри комментария. Таким способом можно отключить любое количество строк кода.

Шебанг комментарии
------------------

Третий специализированный синтаксис комментариев, **шебанг комментарий**, в процессе стандартизации в ECMAScript (смотреть Hashbang Grammar proposal).

Шебанг комментарий ведёт себя точно также как и однострочный (`//`) комментарий. Вместо этого, он начинается с `#!` и **действителен только в самом начале скрипта или модуля**. Обратите внимание, что никакие пробелы не разрешены перед `#!`. Комментарий состоит из всех символов после `#!` до конца первой строки; только такой комментарий разрешён.

Шебанг комментарий определяет путь к JavaScript интерпретатору, скрипт которого вы хотите выполнить. Пример, как это работает:

```js
#!/usr/bin/env node

console.log("Hello world");
```

**Примечание:** Hashbang comments in JavaScript mimic shebangs in Unix used to run files with proper interpreter.

**Предупреждение:** Although BOM before hashbang comment will work in a browser it is not advised to use BOM in a script with hasbang. BOM will not work when you try to run the script in Unix/Linux. So use UTF-8 without BOM if you want to run scripts directly from shell.

Для определения JavaScript интерпретатора используйте только `#!` . В любых других случаях используйте `//` (или многострочный комментарий).

Ключевые слова
--------------

### Зарезервированные ключевые слова в ECMAScript 2015

* `break`
* `case`
* `class`
* `catch`
* `const`
* `continue`
* `debugger`
* `default`
* `delete`
* `do`
* `else`
* `export`
* `extends`
* `finally`
* `for`
* `function`
* `if`
* `import`
* `in`
* `instanceof`
* `let`
* `new`
* `return`
* `super`
* `switch`
* `this`
* `throw`
* `try`
* `typeof`
* `var`
* `void`
* `while`
* `with`
* `yield`
### Ключевые слова, зарезервированные на будущее

Следующие ключевые слова зарезервированы на будущее ECMAScript спецификацией. За ними сейчас не стоит никакой функциональности, но она может появиться в будущих версиях, поэтому эти ключевые слова не могут быть использованы, как идентификаторы. Эти ключевые слова не могут быть использованы даже в strict или non-strict режимах.

* `enum`
* `await`

Следующие ключевые слова зарезервированы для кода, который выполняется в strict режиме:

* `implements`
* `package`
* `protected`
* `static`
* `interface`
* `private`
* `public`
### Зарезервированные ключевые слова в более старых версиях

Перечисленные ниже ключевые слова зарезервированы для старых версий ECMAScript спецификаций (ECMAScript от 1 по 3).

* `abstract`
* `boolean`
* `byte`
* `char`
* `double`
* `final`
* `float`
* `goto`
* `int`
* `long`
* `native`
* `short`
* `synchronized`
* `transient`
* `volatile`

К тому же, литералы `null`, `true`, и `false` зарезервированы в ECMAScript для их обычной функциональности.

### Использование зарезервированных слов

Зарезервированные слова действительно применяются только к идентификаторам **(vs. IdentifierNames)**. Как описано в es5.github.com/#A.1, это все имена IdentifierNames, которые не исключают зарезервированных слов.

```js
a.import
a["import"]
a = { import: "test" }.
```

С другой стороны, следующее выражение неправильно, т.к. Идентификатор `IdentifierName` не содержит зарезервированных слов. Идентификаторы используются для `FunctionDeclaration, FunctionExpression, VariableDeclaration` и т.п., в то время, как `IdentifierNames` используются для `MemberExpression, CallExpression` и т.п.

```js
function import() {} // неправильно.
```

Литералы
--------

### Литерал Null

Подробнее о ``null`null`.

```js
null;
```

### Литерал Boolean

Подробнее о ``Boolean``.

```js
true;
false;
```

### Литералы чисел

#### Decimal (десятичные числа)

```js
1234567890;
42;

// Будьте осторожны с использованием нуля вначале числа:

0888; // 888 распознается, как десятичное число
0777; // распознается, как восьмеричное число, 511 - как десятичное число
```

Имейте в виду, что литералы десятичных чисел могут начинаться с нуля (0), за которым следует другое десятичное число, но в случае, если число начинается с нуля и за ним идёт цифра меньше 8, то число будет распознано как восьмеричное. This won't throw in JavaScript, see Firefox bug 957513. See also the page about ``parseInt()``.

#### Binary (двоичные числа)

Синтаксис двоичных чисел состоит из цифры ноль, за которой следует маленькая или большая латинская буква "B" (0b или 0B). Этот синтаксис новый и появился только в ECMAScript 2015, пожалуйста посмотрите таблицу совместимости с браузерами. Это может производить ошибку ``SyntaxError``: "Missing binary digits after 0b", Если цифры не 0 или 1.

```js
var FLT\_SIGNBIT = 0b10000000000000000000000000000000; // 2147483648
var FLT\_EXPONENT = 0b01111111100000000000000000000000; // 2139095040
var FLT\_MANTISSA = 0b00000000011111111111111111111111; // 8388607
```

#### Octal (восьмеричные числа)

Восьмеричный числовой синтаксис, который использует 0 с последующей, в нижнем или верхнем регистре, латинскую букву "О" (`0o` или `0O)`. Этот синтаксис появился в ECMAScript 2015, пожалуйста, посмотрите таблицу совместимости с браузерами. Это может производить ошибку `SyntaxError`: "Missing octal digits after 0o", если цифры не между 0 и 7.

```js
var n = 0o755; // 493
var m = 0o644; // 420

// Так же возможно с лидирующими нулями (см. заметку о десятичных дробях выше)
0755;
0644;
```

#### Hexadecimal (шестнадцатеричные числа)

Шестнадцатеричный числовой синтаксис, который использует 0 с последующей, в нижнем или верхнем регистре, латинскую букву "X" (`0x` или `0X)`. Если числа после 0x вне диапазона (0123456789ABCDEF), то может последовать за этим `SyntaxError`: "Identifier starts immediately after numeric literal".

```js
0xfffffffffffffffff; // 295147905179352830000
0x123456789abcdef; // 81985529216486900
0xa; // 10
```

### Литерал Object (Объект)

Смотрите также `Object` и `Object initializer` для получения более подробной информации.

```js
var o = { a: "foo", b: "bar", c: 42 };

// сокращённая нотация. Появилась в ES2015
var a = "foo",
  b = "bar",
  c = 42;
var o = { a, b, c };
// вместо
var o = { a: a, b: b, c: c };
```

### Литерал Array (Массив)

Смотрите также `Array` для получения более подробной информации.

```js
[1954, 1974, 1990, 2014];
```

### Литерал String (Строка)

```js
'foo';
"bar";
```

#### Экранирование шестнадцатеричной последовательности

```js
"\xA9"; // "©"
```

#### Экранирование Юникод символов

Для экранирования Юникод символов обязательно нужно указать по крайней мере 4 символа после \u.

```js
"\u00A9"; // "©"
```

#### Unicode code point escapes

Новое в ECMAScript 2015. With Unicode code point escapes, any character can be escaped using hexadecimal numbers so that it is possible to use Unicode code points up to `0x10FFFF`. With simple Unicode escapes it is often necessary to write the surrogate halves separately to achieve the same.

See also `String.fromCodePoint()` or `String.prototype.codePointAt()`.

```js
"\u{2F804}";

// the same with simple Unicode escapes
"\uD87E\uDC04";
```

### Литерал Регулярного выражения

Смотрите также ``RegExp`` для получения более подробной информации.

```js
/ab+c/g

// An "empty" regular expression literal
// The empty non-capturing group is necessary
// to avoid ambiguity with single-line comments.
/(?:)/
```

### Литерал Шаблона

Смотрите также `template strings` для получения более подробной информации.

```js
`string text`;

`string text line 1
 string text line 2`;

`string text ${expression} string text`;

tag`string text ${expression} string text`;
```

Автоматическая вставка "точки с запятой"
----------------------------------------

Некоторые `JavaScript условия` должны быть завершены точкой с запятой и поэтому на них влияет автоматическая вставка точки с запятой (ASI):

* Пустое условие
* `let`, `const`, переменные
* `import`, `export`, объявление модулей
* Оператор-выражение
* `debugger`
* `continue`, `break`, `throw`
* `return`

1. Точка с запятой ставится до, когда ограничитель строки или "}" is encountered that is not allowed by the grammar.

```js
{ 1 2 } 3

// согласно ASI, будет преобразовано в

{ 1 2 ;} 3;
```

2. Точка с запятой ставится в конце, когда обнаружен конец вводимой строки токенов и парсер is unable to parse the single input stream as a complete program.

Here `++` is not treated as a `postfix operator` (en-US) applying to variable `b`, because a line terminator occurs between `b` and `++`.

```js
a = b
++c

// согласно ASI, будет преобразовано в

a = b;
++c;
```

3. Точка с запятой вставляется в конце, когда согласно инструкции с ограниченным производством в грамматике следует ограничитель строки. Эти утверждения с правилами «no LineTerminator here» здесь:

* PostfixExpressions (`++` and `--`)
* `continue`
* `break`
* `return`
* `yield`, `yield*`
* `module`

```js
return
a + b

// согласно ASI, будет преобразовано в

return;
a + b;
```

Спецификации
------------

| Specification |
| --- |
| ECMAScript Language Specification  |

Совместимость с браузерами
--------------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

Особенности Firefox
-------------------

* Prior to Firefox 5 (JavaScript 1.8.6), future reserved keywords could be used when not in strict mode. This ECMAScript violation was fixed in Firefox 5.
Смотрите также
--------------

* Jeff Walden: Двоичные и восьмеричные числа
* Mathias Bynens: JavaScript character escape sequences
* `Boolean`
* `Number`
* `RegExp`
* `String`