getter - JavaScript

getter
======

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

Интерактивный пример
--------------------

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

{get prop() { ... } }
{get [expression]() { ... } }
```

### Параметры

`prop`

Имя свойства для привязывания к заданной функции.

`expression`

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

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

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

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

Учтите следующее при работе с синтаксисом `get`:

* Он может иметь идентификатор, который является либо числом, либо строкой;
* Он должен иметь ровно 0 параметров (смотрите Incompatible ES5 change: literal getter and setter functions must now have exactly zero or one arguments для доп. информации);
* Он не должен появляться в объектном литерале вместе с другим get или через ввод данных для того же свойства (`{ get x() { }, get x() { } }` и `{ x: ..., get x() { } }` запрещены).

Геттер можно удалить при помощи оператора `delete`.

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

### Определение геттера на новом объекте в момент инициализации этого объекта

Ниже создаётся псевдо-свойство `latest` для объекта `obj`, который выведет последний элемент массива в консоль лог.

```js
const obj = {
  log: ["example", "test"],
  get latest() {
    if (this.log.length === 0) return undefined;
    return this.log[this.log.length - 1];
  },
};
console.log(obj.latest); // "test"
```

Обратите внимание, что попытка присвоить значение `latest` не изменит его.

### Удаление геттера оператором delete

`Если вы хотите удалить геттер, используйте delete`:

```js
delete obj.latest;
```

### Определение геттера на уже существующих объектах с помощью `defineProperty`

Для добавления геттера к существующему объекту в любое время используйте Object.defineProperty().

```js
const o = { a: 0 };

Object.defineProperty(o, "b", {
  get: function () {
    return this.a + 1;
  },
});

console.log(o.b); // Runs the getter, which yields a + 1 (which is 1)
```

### Использование вычисляемого именованного свойства

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

```js
var expr = "foo";

var obj = {
  get [expr]() {
    return "bar";
  },
};

console.log(obj.foo); // "bar"
```

### Умные / самостоятельно перезаписывающиеся/ ленивые геттеры

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

Дополнительная техника оптимизации заключается в том, чтобы лениться или откладывать вычисление значения свойства и кешировать его для дальнейшего доступа. Так поступают **умные или запоминающие геттеры**. Значение вычисляется в первый раз при вызове геттера и затем сохраняется в кеше так, что последующие обращения будут возвращать кешированные значения без его пересчёта. Это полезно в следующих ситуациях:

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

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

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

```js
get notifier() {
  delete this.notifier;
  return this.notifier = document.getElementById("bookmarked-notification-anchor");
},
```

Для Firefox смотрите также модуль XPCOMUtils.jsm , который определяет функцию `defineLazyGetter()`.

### `get` и `defineProperty`

Использование ключевого слова `get` и `Object.defineProperty()` даёт похожие результаты, но при использовании в `classes` между ними есть тонкая разница.

При использовании `get` свойство будет определено в прототипе объекта, в то время, как при использовании `Object.defineProperty ()` свойство будет определено в экземпляре, к которому применяется.

```js
class Example {
  get hello() {
    return "world";
  }
}

const obj = new Example();
console.log(obj.hello);
// "world"
console.log(Object.getOwnPropertyDescriptor(obj, "hello"));
// undefined
console.log(
  Object.getOwnPropertyDescriptor(Object.getPrototypeOf(obj), "hello"),
);
// { configurable: true, enumerable: false, get: function get hello() { return 'world'; }, set: undefined }
```

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

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

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

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

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

* сеттер
* `delete`
* `Object.defineProperty()`
* `Object.prototype.__defineGetter__()`
* `Object.prototype.__defineSetter__()`
* Defining Getters and Setters in JavaScript Guide


Остаточные параметры (rest parameters) - JavaScript

Остаточные параметры (rest parameters)
======================================

Синтаксис **остаточных параметров** функции позволяет представлять неограниченное множество аргументов в виде массива.

Интерактивный пример
--------------------

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

```js
function(a, b, ...theArgs) {
  // ...
}
```

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

Если последний именованный аргумент функции имеет префикс `...`, он автоматически становится массивом с элементами от `0` до `theArgs.length-1` в соответствии с актуальным количеством аргументов, переданных в функцию.

```js
function myFun(a, b, ...manyMoreArgs) {
  console.log("a", a);
  console.log("b", b);
  console.log("manyMoreArgs", manyMoreArgs);
}

myFun("один", "два", "три", "четыре", "пять", "шесть");

// Console Output:
// a, один
// b, два
// manyMoreArgs, [три, четыре, пять, шесть]
```

### Отличия остаточных параметров от объекта `arguments`

Существует три основных отличия остаточных параметров от объекта `arguments`:

* остаточные параметры включают только те, которым не задано отдельное имя, в то время как объект `arguments` содержит все аргументы, передаваемые в функцию;
* объект `arguments` не является массивом, в то время как остаточные параметры являются экземпляром `Array` и методы `sort`, `map`, `forEach` или `pop` могут непосредственно у них использоваться;
* объект `arguments` имеет дополнительную функциональность, специфичную только для него (например, свойство `callee`).
### Из аргументов в массив

Остаточные параметры были введены для уменьшения количества шаблонного кода:

```js
// До появления остаточных параметров "arguments" конвертировали в обычный массив используя:

function f(a, b) {
  var normalArray = Array.prototype.slice.call(arguments);
  // -- или --
  var normalArray = [].slice.call(arguments);
  // -- или --
  var normalArray = Array.from(arguments);

  var first = normalArray.shift(); // OK, даёт первый аргумент
  var first = arguments.shift(); // ERROR (arguments не является обычным массивом)
}

// Теперь мы можем легко получить остаточные параметры как обычный массив

function f(...args) {
  var normalArray = args;
  var first = normalArray.shift(); // OK, даёт первый аргумент
}
```

### Деструктуризация остаточных параметров

Остаточные параметры могут быть деструктурированы (только массивы). Это означает, что их данные могут быть заданы как отдельные значения. Смотрите Деструктурирующее присваивание.
```

function f(...[a, b, c]) {
  return a + b + c;
}

f(1)          // NaN (b и c равны undefined)
f(1, 2, 3)    // 6
f(1, 2, 3, 4) // 6 (четвёртый параметр не деструктурирован)
```

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

В этом примере первый аргумент задан как `"a"`, второй как `"b"`, так что эти аргументы используются как обычно. Однако третий аргумент `"manyMoreArgs"` будет массивом, который содержит 3-й, 4-й, 5-й, 6-й ... n-й аргументы, которые передаст пользователь.

```js
function myFun(a, b, ...manyMoreArgs) {
  console.log("a", a);
  console.log("b", b);
  console.log("manyMoreArgs", manyMoreArgs);
}

myFun("один", "два", "три", "четыре", "пять", "шесть");

// a, один
// b, два
// manyMoreArgs, [три, четыре, пять, шесть]
```

Ниже... даже если передано одно значение последним аргументом, оно всё равно помещается в массив.

```js
// использование той же функции, что и в примере выше

myFun("один", "два", "три");

// a, один
// b, два
// manyMoreArgs, [три]
```

Ниже... третий аргумент не был передан, но "manyMoreArgs" всё ещё массив (хотя и пустой).

```js
// использование той же функции, что и в примере выше

myFun("один", "два");

// a, один
// b, два
// manyMoreArgs, []
```

Поскольку `theArgs` является массивом, количество элементов в нём определяется свойством `length`:

```js
function fun1(...theArgs) {
  console.log(theArgs.length);
}

fun1(); // 0
fun1(5); // 1
fun1(5, 6, 7); // 3
```

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

```js
function multiply(multiplier, ...theArgs) {
  return theArgs.map(function (element) {
    return multiplier \* element;
  });
}

var arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]
```

Методы `Array` могут быть использованы на остаточных параметрах, но не на объекте `arguments`:

```js
function sortRestArgs(...theArgs) {
  var sortedArgs = theArgs.sort();
  return sortedArgs;
}

console.log(sortRestArgs(5, 3, 7, 1)); // 1, 3, 5, 7

function sortArguments() {
  var sortedArgs = arguments.sort();
  return sortedArgs; // это никогда не выполнится
}

console.log(sortArguments(5, 3, 7, 1)); // TypeError (arguments.sort is not a function)
```

Чтобы использовать методы `Array` на объекте `arguments`, нужно преобразовать его в настоящий массив.

```js
function sortArguments() {
  var args = Array.from(arguments);
  var sortedArgs = args.sort();
  return sortedArgs;
}
console.log(sortArguments(5, 3, 7, 1)); // 1, 3, 5, 7
```

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

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

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

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

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

* Объект arguments
* Array
* Функции
* Оператор распространения
* Оригинальное предложение на ecmascript.org
* JavaScript arguments object and beyond


Стрелочные функции - JavaScript

Стрелочные функции
==================

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

**Выражения стрелочных функций** имеют более короткий синтаксис по сравнению с функциональными выражениями и лексически привязаны к значению this (но не привязаны к собственному this, arguments, super, или new.target). Выражение стрелочных функций не позволяют задавать имя, поэтому стрелочные функции анонимны, если их ни к чему не присвоить.

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

### Базовый синтаксис

```js
(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
// эквивалентно: (param1, param2, …, paramN) => { return expression; }

// Круглые скобки не обязательны для единственного параметра:
(singleParam) => { statements }
singleParam => { statements }

// Функция без параметров нуждается в круглых скобках:
() => { statements }
() => expression
// Эквивалентно: () => { return expression; }
```

### Расширенный синтаксис

```js
// Когда возвращаете литеральное выражение объекта, заключите тело в скобки
params => ({foo: bar})

// Остаточные параметры и параметры по умолчанию поддерживаются
(param1, param2, ...rest) => { statements }
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => { statements }

// Деструктуризация тоже поддерживается
var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f();  // 6
```

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

Смотрите также "ES6 In Depth: Arrow functions" on hacks.mozilla.org.

Два фактора повлияли на появление стрелочных функции: более короткий синтаксис и лексика `this`.

### Короткие функции

В некоторых функциональных шаблонах приветствуются более короткие функции. Сравните:

```js
var elements = ["Hydrogen", "Helium", "Lithium", "Beryllium"];

elements.map(function (element) {
  return element.length;
}); // Это выражение вернёт массив [8, 6, 7, 9]

// Функцию выше можно записать как стрелочную функцию:
elements.map((element) => {
  return element.length;
}); // [8, 6, 7, 9]

// Если единственным оператором в выражении стрелочной функции является return,
// можно удалить return и окружающие фигурные скобки

elements.map((element) => element.length); // [8, 6, 7, 9]

// В данном случае, поскольку нам нужно только свойство length, мы можем использовать деструктуризированный параметр:
// Обратите внимание, что строка `"length"` соответствует свойству, которое мы хотим получить,
// в то время как `lengthFooBArX` это просто имя переменной, которую можно назвать как вы хотите
elements.map(({ length: lengthFooBArX }) => lengthFooBArX); // [8, 6, 7, 9]

// Это задание деструктуризированного параметра может быть записано, как показано ниже. Тем не менее, обратите внимание,
// что нет строки `"length"`, чтобы выбрать, какое свойство мы хотим получить. Вместо этого в качестве свойства,
// которое мы хотим извлечь из объекта, используется само литеральное имя переменной `length`
elements.map(({ length }) => length); // [8, 6, 7, 9]
```

### Отсутствие связывания с `this`

До появления стрелочных функций, каждая новая функция имела своё значение `this` (новый объект в случае конструктора, undefined в strict режиме вызова функции, контекст объекта при вызове функции как "метода объекта" и т.д.). Это очень раздражало при использовании объектно-ориентированного стиля программирования.

```js
function Person() {
  // В конструкторе Person() `this` указывает на себя.
  this.age = 0;

  setInterval(function growUp() {
    // В нестрогом режиме, в функции growUp() `this` указывает
    // на глобальный объект, который отличается от `this`,
    // определяемом в конструкторе Person().
    this.age++;
  }, 1000);
}

var p = new Person();
```

В ECMAScript 3/5, данная проблема решалась присваиванием значения `this` переменной:

```js
function Person() {
  var that = this;
  that.age = 0;

  setInterval(function growUp() {
    // Функция с обратным вызовом(callback) содержит переменную that, которая
    // ссылается на требуемый объект this.
    that.age++;
  }, 1000);
}
```

Кроме этого, может быть создана привязанная функция, в которую передаётся требуемое значение `this` для функции (функция `growUp()` в примере выше).

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

```js
function Person() {
  this.age = 0;

  setInterval(() => {
    this.age++; // `this` указывает на объект Person
  }, 1000);
}

var p = new Person();
```

#### Строгий режим исполнения

Поскольку значение `this` определяется лексикой, правила строгого режима (strict mode) относительно `this` игнорируются:

```js
var f = () => {
  "use strict";
  return this;
};
f() === window; // или глобальный объект
```

Все остальные правила строгого режима применяются как обычно.

#### Вызов с помощью call или apply

Так как значение `this` определяется лексикой, вызов стрелочных функций с помощью методов `call()` или `apply()`, даже если передать аргументы в эти методы, не влияет на значение `this`:

```js
var adder = {
  base: 1,

  add: function (a) {
    var f = (v) => v + this.base;
    return f(a);
  },

  addThruCall: function (a) {
    var f = (v) => v + this.base;
    var b = {
      base: 2,
    };

    return f.call(b, a);
  },
};

console.log(adder.add(1)); // Выводит 2
console.log(adder.addThruCall(1)); // Всё равно выводит 2
```

### Не имеет собственного объекта arguments

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

```js
var arguments = 42;
var arr = () => arguments;

arr(); // 42

function foo() {
  var f = (i) => arguments[0] + i; // Неявное связывание ссылки arguments
  // стрелочной функции f
  // c объектом arguments функции foo
  return f(2);
}

foo(1); // 3
```

В большинстве случаев лучшей заменой объекта arguments в стрелочных функциях являются остаточные параметры:

```js
function foo() {
  var f = (...args) => args[0];
  return f(2);
}

foo(1); // 2
```

### Использование стрелочных функций как методов

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

```js
"use strict";
var obj = {
  i: 10,
  b: () => console.log(this.i, this),
  c: function () {
    console.log(this.i, this);
  },
};
obj.b(); // prints undefined, Window {...} (или глобальный объект)
obj.c(); // prints 10, Object {...}
```

Стрелочные функции не объявляют привязку ("bind") их контекста `this`. Другой пример включает `Object.defineProperty()`:

```js
"use strict";
var obj = {
  a: 10,
};

Object.defineProperty(obj, "b", {
  get: () => {
    console.log(this.a, typeof this.a, this);
    return this.a + 10;
    // представляет глобальный объект 'Window', но 'this.a' возвращает 'undefined'
  },
});
```

### Использование оператора `new`

Стрелочные функции не могут быть использованы как конструктор и вызовут ошибку при использовании с `new`:

```js
var a = new (function () {})();
// переменной "a" будет присвоено значение экземпляра анонимной функции

var b = new (() => {})();
// будет выброшено исключение
// Uncaught TypeError: (intermediate value) is not a constructor
```

### Использование ключевого слова `yield`

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

Тело функции
------------

Тело стрелочной функции может иметь краткую (concise body) или блочную (block body) форму.

Блочная форма не возвращает значение, необходимо явно вернуть значение.

```js
var func = (x) => x \* x; // краткий синтаксис,
// неявно возвращает результат
var func = (x, y) => {
  return x + y;
}; // блочный синтаксис,
// явно возвращает результат
```

Возвращаемые объектные строки (литералы)
----------------------------------------

Помните о том, что возвращаемые объектные строки используют сокращённый синтаксис: `params => {object:literal}` будет работать не так, как ожидается.

```js
var func = () => { foo: 1 };
// Вызов func() возвращает undefined!

var func = () => { foo: function() {} };
// SyntaxError: function statement requires a name
```

Это происходит потому что код в скобках ({}) распознаётся как цепочка выражений (т.е. `foo` трактуется как наименование, а не как ключ в объектной строке).

Не забывайте оборачивать скобками объектные строки.

```js
var func = () => ({ foo: 1 });
```

Разрывы строк
-------------

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

```js
var func = ()
           => 1;
// SyntaxError: expected expression, got '=>'
```

Разбор порядка следования
-------------------------

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

```js
let callback;

callback = callback || function() {}; // ok

callback = callback || () => {};
// SyntaxError: invalid arrow-function arguments

callback = callback || (() => {});    // ok
```

Больше примеров
---------------

```js
// Пустая стрелочная функция возвращает undefined
let empty = () => {};

(() => "foobar")();
// Вернёт "foobar"
// (Это Immediately Invoked Function Expression
// смотри 'IIFE' в справочнике)

var simple = (a) => (a > 15 ? 15 : a);
simple(16); // 15
simple(10); // 10

let max = (a, b) => (a > b ? a : b);

// Удобные операции над массивами: filter, map, ...

var arr = [5, 6, 13, 0, 1, 18, 23];

var sum = arr.reduce((a, b) => a + b);
// 66

var even = arr.filter((v) => v % 2 == 0);
// [6, 0, 18]

var double = arr.map((v) => v \* 2);
// [10, 12, 26, 0, 2, 36, 46]

// Более короткие цепочки promise-ов
promise
  .then((a) => {
    // ...
  })
  .then((b) => {
    // ...
  });

// Стрелочные функции без параметров, которые визуально легче разбирать
setTimeout(() => {
  console.log("Я буду раньше");
  setTimeout(() => {
    // deeper code
    console.log("Я буду позже");
  }, 1);
}, 1);
```

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

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

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

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

### Замечания для Firefox

* Первоначальная реализация стрелочных функций в Firefox автоматически переводила их в строгий режим. Это поведение было изменено в Firefox 24 (en-US). Использование `"use strict";` стало обязательным.
* Стрелочные функции семантически отличаются от нестандартных Expression Closures, добавленных в Firefox 3 (подробности в Javascript 1.8); в Expression Closures значение `this` не привязано лексически.
* До Firefox 39, перенос строки (`\n`) был ошибочно разрешён после аргументов стрелочной функции. Это было исправлено для соблюдения спецификации ES2015, и код вроде: `() \n => {}` теперь вызывает `SyntaxError` в этой и более поздних версиях.
See also
--------

* "ES6 In Depth: Arrow functions" on hacks.mozilla.org


Определение методов - JavaScript

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

Начиная с ECMAScript 6, существует короткий синтаксис для определения методов в инициализаторе объекта. По сути, это сокращение для функции, которая назначена имени метода.

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

var obj = {
  property([parameters]) {},
  get property() {},
  set property(value) {},
  * generator() {}
};
```

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

Короткий синтаксис похожий на синтаксис getter'ов и setter'ов представленных в ECMAScript 5.

Следующий код:

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

Вы теперь можете сократить до:

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

### Сокращение методов-генераторов

Методы-генераторы также могут быть определены используя короткий синтаксис. Обратите внимание, что звёздочка (\*) в коротком синтаксисе должна быть перед именем свойства генератора. То есть, `* g(){}` будет работать, а `g *(){}` не будет.

```js
// Используя свойство с именем (pre-ES6)
var obj2 = {
  g: function\* () {
    var index = 0;
    while (true) yield index++;
  },
};

// Тот же объект используя короткий синтаксис
var obj2 = {
  \*g() {
    var index = 0;
    while (true) yield index++;
  },
};

var it = obj2.g();
console.log(it.next().value); // 0
console.log(it.next().value); // 1
```

### Определения методов (ES6) не могут быть конструкторами

Все определения методов кроме методов-генераторов не могут быть конструкторами и будут выбрасывать `TypeError` если вы попытаетесь создать их экземпляр.

```js
var obj = {
  method() {},
};
new obj.method(); // TypeError: obj.method is not a constructor

var obj = {
  \*g() {},
};
new obj.g(); // Генератор
```

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

### Простой тестовый пример

```js
var obj = {
  a: "foo",
  b() {
    return this.a;
  },
};
console.log(obj.b()); // "foo"
```

### Вычисляемые имена свойств

Короткий синтаксис также поддерживает вычисляемые имена свойств.

```js
var bar = {
  foo0: function () {
    return 0;
  },
  foo1() {
    return 1;
  },
  ["foo" + 2]() {
    return 2;
  },
};

console.log(bar.foo0()); // 0
console.log(bar.foo1()); // 1
console.log(bar.foo2()); // 2
```

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

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

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

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

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

* `get`
* `set`
* Lexical grammar


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

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

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

Интерактивный пример
--------------------

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

function [name]([param1[ = defaultValue1 ][, ..., paramN[ = defaultValueN ]]]) {
   statements
}
```

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

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

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

В приведённом ниже примере, в случае если при вызове функции значение для параметра `b` не передавалось, его значением становилось `undefined`, и результатом вычисления `a * b` в функции `multiply` получалось значение `NaN`.

```js
function multiply(a, b) {
  return a \* b;
}

multiply(5, 2); // 10
multiply(5); // NaN !
```

Чтобы такого не происходило, в теле функции использовался код подобный тому, что находится во второй строчке, где в случае, если функция `multiply` вызывалась только c одним аргументом, параметру `b` присваивалось значение `1`:

```js
function multiply(a, b) {
  b = typeof b !== "undefined" ? b : 1;
  return a \* b;
}

multiply(5, 2); // 10
multiply(5); // 5
```

С появлением в ES2015 параметров по умолчанию стало возможным обходиться без проверки параметров в теле функции. Так, в приведённом выше примере достаточно в заголовке функции указать `1` в качестве значения по умолчанию для параметра `b`:

```js
function multiply(a, b = 1) {
  return a \* b;
}

multiply(5, 2); // 10
multiply(5); // 5
multiply(5, undefined); // 5
```

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

### Передача значения `undefined` в сравнении с передачей других "ложных" значений

Значение по умолчанию присваивается формальному параметру только если при вызове функции значение для данного параметра не было передано или было явным образом передано `undefined`. Если формальному параметру при вызове передано любое значение, отличное от `undefined`, в том числе одно из "ложных" значений, таких как `false`, `0`, `""`, `''`, ````, `null`, `NaN`, то в этом случае значение по умолчанию присвоено параметру не будет. Это иллюстрирует следующий пример:

```js
function test(num = 1) {
  console.log(typeof num);
}

// num не передано, или передано undefined:
test(); // 'number' (num получил значение 1)
test(undefined); // 'number' (и здесь num получил значение 1)

// num передано значение null или другое "ложное" значение:
test(""); // 'string' (num получил значение '')
test(null); // 'object' (num получил значение null)
```

### Параметры по умолчанию вычисляются в момент вызова функции

В Javascript параметры по умолчанию вычисляются в момент вызова функции. В отличие от языка Python, при каждом вызове функции создаётся новое лексическое окружение функции.

```js
function append(value, array = []) {
  array.push(value);
  return array;
}

append(1); // [1]
append(2); // [2], а не [1, 2]
```

Это верно и для функций, и для переменных:

```js
function callSomething(thing = something()) {
  return thing;
}

let numberOfTimesCalled = 0;
function something() {
  numberOfTimesCalled += 1;
  return numberOfTimesCalled;
}

callSomething(); // 1
callSomething(); // 2
```

### Параметры по умолчанию доступны в следующих параметрах по умолчанию

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

```js
function greet(name, greeting, message = greeting + " " + name) {
  return [name, greeting, message];
}

greet("David", "Hi"); // ["David", "Hi", "Hi David"]
greet("David", "Hi", "Happy Birthday!"); // ["David", "Hi", "Happy Birthday!"]
```

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

```js
function go() {
  return ":P";
}

function withDefaults(
  a,
 b = 5,
 c = b,
 d = go(),
 e = this,
 f = arguments,
 g = this.value,
) {
  return [a, b, c, d, e, f, g];
}
function withoutDefaults(a, b, c, d, e, f, g) {
  switch (arguments.length) {
    case 0:
      a;
    case 1:
      b = 5;
    case 2:
      c = b;
    case 3:
      d = go();
    case 4:
      e = this;
    case 5:
      f = arguments;
    case 6:
      g = this.value;
    default:
  }
  return [a, b, c, d, e, f, g];
}

withDefaults.call({ value: "=^\_^=" });
// [undefined, 5, 5, ":P", {value:"=^\_^="}, arguments, "=^\_^="]

withoutDefaults.call({ value: "=^\_^=" });
// [undefined, 5, 5, ":P", {value:"=^\_^="}, arguments, "=^\_^="]
```

### Инициализация с помощью функций, определяемых в теле функции

Начиная с версии Gecko 33 функции, определяемые в теле самой функции, не могут быть использованы для инициализации параметров по умолчанию; попытка это сделать приведёт к ошибке `ReferenceError`. Параметры по умолчанию всегда вычисляются до обработки описаний функций, определяемых в теле функции.

```js
// Вызовет ошибку ReferenceError!
function f(a = go()) {
  function go() {
    return ":P";
  }
}
f(); // ReferenceError: go is not defined
```

### Параметры без инициализации, следующие после инициализируемых параметров

До появления версии Gecko 26, следующий код приводил к `SyntaxError`. Это было исправлено в Firefox bug 777060 и с тех пор работает корректно. Аргументы, передаваемые при вызове функции, становятся значениями формальных параметров независимо от наличия у последних инициализации по умолчанию, а также независимо от присутствия у функции других параметров, находящихся правее в списке параметров и не имеющих инициализации.

```js
function f(x = 1, y) {
  return [x, y];
}

f(); // [1, undefined];
f(2); // [2, undefined];
```

### Инициализация по умолчанию деструктурированных параметров

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

```js
function f([x, y] = [1, 2], { z: z } = { z: 3 }) {
  return x + y + z;
}

f(); // 6
```

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

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

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

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

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

* Оригинальное предложение на ecmascript.org


Объект arguments - JavaScript

Объект arguments
================

Объект **`arguments`** — это подобный массиву объект, который содержит аргументы, переданные в функцию.

**Примечание:** Если вы пишете ES6-совместимый код, то лучше использовать остаточные параметры.

**Примечание:** "Подобный массиву" означает, что `arguments` имеет свойство `length`, а элементы индексируются начиная с нуля. Но при этом он не может обращаться к встроенным методам `Array`, таким как `forEach()` или `map()`. Подробнее об этом в §Описании.

Интерактивный пример
--------------------

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

arguments
```

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

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

```js
arguments[0];
arguments[1];
arguments[2];
```

Аргументам может быть присвоено значение:

```js
arguments[1] = "new value";
```

Объект `arguments` не является `Array`. Он похож на массив, но не обладает ни одним из его свойств, кроме `length`. Например, у него нет метода `pop`. Однако, он может быть преобразован в обычный массив:

```js
var args = Array.prototype.slice.call(arguments);
var args = [].slice.call(arguments);

// ES2015
const args = Array.from(arguments);
const args = [...arguments];
```

**Предупреждение:** Использование `slice` на объекте `arguments` не позволяет сделать оптимизации в некоторых JavaScript движках (например, V8 — подробнее). Если они важны, можно попробовать вместо этого создать новый массив с аналогичной длиной и заполнить его элементами объекта `arguments.` Альтернативный вариант — использовать конструктор `Array` как функцию:

```js
var args =
  arguments.length === 1 ? [arguments[0]] : Array.apply(null, arguments);
```

Объект `arguments` можно использовать при вызове функции с бо́льшим количеством аргументов, чем было предусмотрено в её объявлении. Такой способ удобен для функций, в которые допустимо передавать переменное количество аргументов. Можно воспользоваться `arguments.length`, чтобы определить количество переданных в функцию аргументов, а затем обработать каждый из них с помощью объекта `arguments`. Чтобы определить количество параметров функции, описанных в её сигнатуре (en-US), можно использовать свойство `Function.length`.

### Использование `typeof` с объектом `arguments`

Применение оператора `typeof` к `arguments` вернёт 'object'.
```

console.log(typeof arguments); // 'object'
```

Определение типов аргументов может быть выполнено применением оператора `typeof` и индексацией.
```

// выведет тип первого аргумента
console.log(typeof arguments[0]);
```

### Использование оператора расширения для объекта `arguments`

Как и с обычными массива-подобными объектами, для преобразования объекта `arguments` в обычный массив можно использовать метод `Array.from()` или оператор расширения:

```js
var args = Array.from(arguments);
var args = [...arguments];
```

Свойства
--------

`arguments.callee`

Ссылка на функцию, которая выполняется в текущий момент.

`arguments.caller`

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

`arguments.length`

Количество переданных в функцию аргументов.

`arguments[@@iterator]` (en-US)

Возвращает новый объект `Array Iterator`, содержащий значения для каждого индекса в массиве.

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

### Создание функции, соединяющей несколько строк

Данный пример описывает функцию, которая соединяет несколько строк. Для этой функции объявлен только один аргумент, определяющий символ-разделитель соединяемых элементов. Функция определена следующим образом:

```js
function myConcat(separator) {
  var args = Array.prototype.slice.call(arguments, 1);
  return args.join(separator);
}
```

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

```js
// возвращает "red, orange, blue"
myConcat(", ", "red", "orange", "blue");

// получает "elephant; giraffe; lion; cheetah"
myConcat("; ", "elephant", "giraffe", "lion", "cheetah");

// выводит "sage. basil. oregano. pepper. parsley"
myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley");
```

### Функция, создающая HTML списки

В данном примере приведена функция, которая создаёт строку с HTML-разметкой для списка. Единственный её аргумент — строка, определяющая вид списка: если его значение равно "u", формируется неупорядоченный (маркированный) список, а если "o" — то упорядоченный (нумерованный):

```js
function list(type) {
  var result = "<" + type + "l><li>";
  var args = Array.prototype.slice.call(arguments, 1);
  result += args.join("</li><li>");
  result += "</li></" + type + "l>"; // конец списка

  return result;
}
```

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

```js
var listHTML = list("u", "One", "Two", "Three");

/\* listHTML:

"<ul><li>One</li><li>Two</li><li>Three</li></ul>"

\*/
```

### Остаточные, деструктурированные и параметры по умолчанию

Объект `arguments` может использоваться совместно с остаточными параметрами, параметрами по умолчанию или деструктурированными параметрами.

```js
function foo(...args) {
  return arguments;
}
foo(1, 2, 3); // { "0": 1, "1": 2, "2": 3 }
```

Тем не менее, в нестрогих функциях **соответствие между их аргументами и объектом `arguments`** существует только в том случае, если функция **не** содержит никаких остаточных параметров, параметров по умолчанию или деструктурированных параметров. Например, в функции, приведённой ниже, используется параметр по умолчанию, и в данном случае возвращаемый результат будет равен 10, а не 100:

```js
function bar(a = 1) {
  arguments[0] = 100;
  return a;
}
bar(10); // 10
```

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

```js
function zoo(a) {
  arguments[0] = 100;
  return a;
}
zoo(10); // 100
```

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

```js
function func(a, b) {
  arguments[0] = 90;
  arguments[1] = 99;
  console.log(a + " " + b);
}

func(1, 2); //90, 99
```

или

```js
function func(a, b) {
  a = 9;
  b = 99;
  console.log(arguments[0] + " " + arguments[1]);
}

func(3, 4); //9, 99
```

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

```js
function func(a, b, c = 9) {
  arguments[0] = 99;
  arguments[1] = 98;
  console.log(a + " " + b);
}

func(3, 4); //3, 4
```

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

| Specification |
| --- |
| ECMAScript Language Specification # sec-arguments-exotic-objects |

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

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

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

* `Function`


setter - JavaScript

setter
======

Оператор **`set`** связывает свойство объекта с функцией, которая будет вызвана при попытке установить это свойство.

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

{set prop(val) { . . . }}
{set [expression](val) { . . . }}
```

### Параметры

`prop`

Имя свойства для привязки к заданной функции.

`val`

Псевдоним переменной, которая хранит значение, неудавшегося определения `prop.`

expression

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

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

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

Обратите внимание на следующие моменты при работе с синтаксисом `set`:

* Он может иметь идентификатор, который является либо числом, либо строкой;
* Он должен иметь ровно один параметр (смотрите Incompatible ES5 change: literal getter and setter functions must now have exactly zero or one arguments для более подробной информации);
* Он не должен объявляться в литерале объекта, с другим набором или вводом данных для того же самого свойства.
 ( `{ set x(v) { }, set x(v) { } }` и `{ x: ..., set x(v) { } }` запрещены)

Сеттер может быть удалён оператором `delete`.

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

### Определение сеттера при инициализации новых объектов

Это позволит определить псевдо-параметр `current` объекта `o`, который задаёт значение, обновляющее значение `log`:

```js
var o = {
  set current(str) {
    this.log[this.log.length] = str;
  },
  log: [],
};
```

`обратите внимание, что current` не определён и любые попытки доступа к нему вернут `undefined`.

### Удаление сеттера оператором `delete`

Если вы хотите удалить сеттер, вы можете просто его `удалить`:

```js
delete o.current;
```

### Определение сеттера для существующих объектов используя `defineProperty`

Чтобы добавить сеттер на существующий объект в любое время, используйте `Object.defineProperty()`.

```js
var o = { a: 0 };

Object.defineProperty(o, "b", {
  set: function (x) {
    this.a = x / 2;
  },
});

o.b = 10; // Запускает сеттер, который присваивает 10 / 2 (5) свойству 'a'
console.log(o.a); // 5
```

### Использование вычисляемого имени свойства

```js
var expr = "foo";

var obj = {
  baz: "bar",
  set [expr](v) {
    this.baz = v;
  },
};

console.log(obj.baz); // "bar"
obj.foo = "baz"; // запускает сеттер
console.log(obj.baz); // "baz"
```

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

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

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

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

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

* getter
* `delete`
* `Object.defineProperty()`
* `Object.prototype.__defineGetter__()`
* `Object.prototype.__defineSetter__()`
* Defining Getters and Setters в руководстве по JavaScript


arguments.callee - JavaScript

arguments.callee
================

Свойство `callee псевдомассива arguments` хранит ссылку на функцию-родитель.

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

**Предупреждение:** **Внимание:** В ES5 strict mode использование `arguments.callee` запрещено.

### Зачем вообще использовать `arguments.callee`?

В ранних версиях javaScript отсутствовала такая фишка, как Named Function Expression и единственным спасением было свойство **callee**. К примеру:

```js
var f = function test() {
  alert(typeof test); //undefined
  alert(typeof arguments.callee); //function
};
```

В нынешние времена, когда мы уже можем работать с *NFE*, надобность в использовании свойства **callee** сама собой отпадает\*\*.\*\*

```js
var f = function test() {
  alert(typeof test); //function
};
```

Действительно незаменимым оно остаётся всего в одной ситуации. Когда мы создаём анонимную функцию напрямую через конструктор *Function.*

```js
var b = new Function("", "alert(typeof arguments.callee)");
```

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

### Использование `arguments.callee` для создания рекурсии

```js
var factorial = function (n) {
  return n == 1 ? 1 : n \* arguments.callee(n - 1);
};

factorial(7);
```

Specifications
--------------

| Specification |
| --- |
| ECMAScript Language Specification # sec-arguments-exotic-objects |

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

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

See also
--------

* `Function`


arguments.length - JavaScript

arguments.length
================

**`arguments.length`** свойство, содержащее число аргументов переданных в функцию.

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

arguments.length
```

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

arguments.length свойство содержащее число аргументов переданных в функцию. Оно может быть больше или меньше опряденного параметра count (см. `Function.length`).

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

### `Использование arguments.length`

В этом примере мы определяем функцию, которая может сложить 2 или более чисел вместе.

```js
function adder(base /\*, n2, ... \*/) {
  base = Number(base);
  for (var i = 1; i < arguments.length; i++) {
    base += Number(arguments[i]);
  }
  return base;
}
```

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

| Specification |
| --- |
| ECMAScript Language Specification # sec-arguments-exotic-objects |

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

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

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

* `Function`
* `Function.length`


Spread syntax - JavaScript

Spread syntax
=============

**Spread syntax** позволяет расширить доступные для итерации элементы (например, массивы или строки) в местах
* для функций: где ожидаемое количество аргументов для вызовов функций равно нулю или больше нуля
* для элементов (литералов массива)
* для выражений объектов: в местах, где количество пар "ключ-значение" должно быть равно нулю или больше (для объектных литералов)
Интерактивный пример
--------------------

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

Для вызовов функций:
```

myFunction(...iterableObj);
```

Для литералов массива или строк:
```

[...iterableObj, '4', 'five', 6];
```

Для литералов объекта (новое в ECMAScript 2018):
```

let objClone = { ...obj };
```

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

### Spread в вызовах функций

#### Замена apply

Обычно используют `Function.prototype.apply` в случаях, когда хотят использовать элементы массива в качестве аргументов функции.

```js
function myFunction(x, y, z) {}
var args = [0, 1, 2];
myFunction.apply(null, args);
```

С **spread syntax** вышеприведённое можно записать как:

```js
function myFunction(x, y, z) {}
var args = [0, 1, 2];
myFunction(...args);
```

Любой аргумент в списке аргументов может использовать **spread syntax**, и его можно использовать несколько раз.

```js
function myFunction(v, w, x, y, z) {}
var args = [0, 1];
myFunction(-1, ...args, 2, ...[3]);
```

#### Apply для new

Вызывая конструктор через ключевое слово `new`, невозможно использовать массив и `apply` **напрямую** (`apply` выполняет `[[Call]]`, а не `[[Construct]]`).Однако благодаря spread syntax, массив может быть с лёгкостью использован со словом `new:`

```js
var dateFields = [1970, 0, 1]; // 1 Jan 1970
var d = new Date(...dateFields);
```

Чтобы использовать `new` с массивом параметров без spread syntax, вам потребуется использование частичного применения:

```js
function applyAndNew(constructor, args) {
  function partial() {
    return constructor.apply(this, args);
  }
  if (typeof constructor.prototype === "object") {
    partial.prototype = Object.create(constructor.prototype);
  }
  return partial;
}

function myConstructor() {
  console.log("arguments.length: " + arguments.length);
  console.log(arguments);
  this.prop1 = "val1";
  this.prop2 = "val2";
}

var myArguments = ["hi", "how", "are", "you", "mr", null];
var myConstructorWithArguments = applyAndNew(myConstructor, myArguments);

console.log(new myConstructorWithArguments());
// (internal log of myConstructor): arguments.length: 6
// (internal log of myConstructor): ["hi", "how", "are", "you", "mr", null]
// (log of "new myConstructorWithArguments"): {prop1: "val1", prop2: "val2"}
```

### Spread в литералах массива

#### Более мощный литерал массива

Без spread syntax, применение синтаксиса литерала массива для создания нового массива на основе существующего недостаточно и требуется императивный код вместо комбинации методов `push`, `splice`, `concat` и т.д. С spread syntax реализация становится гораздо более лаконичной:

```js
var parts = ["shoulders", "knees"];
var lyrics = ["head", ...parts, "and", "toes"];
// ["head", "shoulders", "knees", "and", "toes"]
```

Аналогично развёртыванию в массиве аргументов, `...` может быть использован повсеместно и многократно в литерале массива.

#### Копирование массива

```js
var arr = [1, 2, 3];
var arr2 = [...arr]; // like arr.slice()
arr2.push(4);

// arr2 becomes [1, 2, 3, 4]
// arr remains unaffected
```

**Примечание:** Spread syntax на самом деле переходит лишь на один уровень глубже при копировании массива. Таким образом, он может не подходить для копирования многоразмерных массивов, как показывает следующий пример: (также как и c `Object.assign()`) и синтаксис spred

```js
const a = [[1], [2], [3]];
const b = [...a];
b.shift().shift(); // 1
// О нет. Теперь на массив "а" относятся также: а
//[[], [2], [3]]
```

#### Лучший способ конкатенации массивов

Для конкатенации массива часто используется `Array.concat`:

```js
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
// Append all items from arr2 onto arr1
arr1 = arr1.concat(arr2);
```

С использованием spread syntax:

```js
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1 = [...arr1, ...arr2];
```

`Array.unshift` часто используется для вставки массива значений в начало существующего массива. Без spread syntax:

```js
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
// Prepend all items from arr2 onto arr1
Array.prototype.unshift.apply(arr1, arr2); // arr1 is now [3, 4, 5, 0, 1, 2]
```

С использованием spread syntax [Следует отметить, что такой способ создаёт новый массив `arr1`. В отличие от `Array.unshift`, исходный массив не мутируется]:

```js
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1 = [...arr2, ...arr1]; // arr1 is now [3, 4, 5, 0, 1, 2]
```

### Spread в литералах объекта

Предложение Rest/Spread Properties for ECMAScript (стадия 4) добавляет свойства spread в литералы объекта. Оно копирует собственные перечисляемые свойства данного объекта в новый объект.

Поверхностное копирование (без прототипа) или объединение объектов теперь возможно с использованием более короткого, чем `Object.assign()`, синтаксиса.

```js
var obj1 = { foo: "bar", x: 42 };
var obj2 = { foo: "baz", y: 13 };

var clonedObj = { ...obj1 };
// Object { foo: "bar", x: 42 }

var mergedObj = { ...obj1, ...obj2 };
// Object { foo: "baz", x: 42, y: 13 }
```

Обратите внимание, что `Object.assign()` запускает setters, а **spread syntax** нет.

Обратите внимание, что вы не можете заменить или имитировать функцию `Object.assign()`:

```js
var obj1 = { foo: "bar", x: 42 };
var obj2 = { foo: "baz", y: 13 };
const merge = (...objects) => ({ ...objects });

var mergedObj = merge(obj1, obj2);
// Object { 0: { foo: 'bar', x: 42 }, 1: { foo: 'baz', y: 13 } }

var mergedObj = merge({}, obj1, obj2);
// Object { 0: {}, 1: { foo: 'bar', x: 42 }, 2: { foo: 'baz', y: 13 } }
```

В приведённом выше примере оператор распространения не работает так, как можно было бы ожидать: он распространяет *массив* аргументов в литерал *объекта* благодаря параметру rest.

### Только для итерируемых объектов

Spread syntax ( кроме случаев spread properties) может быть применён только к итерируемым объектам (iterable objects) :

```js
var obj = { key1: "value1" };
var array = [...obj]; // TypeError: obj is not iterable
```

### Spread с большим количеством значений

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

Rest синтаксис (параметры)
--------------------------

Синтаксис для rest оператора выглядит таким же как и для spread оператора, однако он используется для деструктуризации массивов и объектов. Фактически, rest оператор противоположен spread оператору: последний раскладывает массив на элементы, тогда как первый собирает много элементов в один. См. rest parameters. (en-US)

Specifications
--------------

| Specification |
| --- |
| ECMAScript Language Specification # prod-SpreadElement |
| ECMAScript Language Specification # prod-ArgumentList |
| ECMAScript Language Specification # prod-PropertyDefinition |

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

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

See also
--------

* Rest parameters (en-US) (also '`...`')
* fn.apply (also '`...`')


super - JavaScript

super
=====

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

Выражения `super.prop` и `super[expr]` действительны в любом определении метода в классах и в литералах объекта.

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

```js
super([arguments]); // вызов родительского конструктора.
super.functionOnParent([arguments]);
```

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

В конструкторе ключевое слово `super()` используется как функция, вызывающая родительский конструктор. Её необходимо вызвать до первого обращения к ключевому слову `this` в теле конструктора. Ключевое слово `super` также может быть использовано для вызова функций родительского объекта.

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

### Использование super в классах

Этот фрагмент кода взят из classes sample (демонстрация). В этом примере `super()` вызывается, чтобы не повторять части конструктора, одинаковые для классов `Rectangle` и `Square`.

```js
class Rectangle {
  constructor(height, width) {
    this.name = "Rectangle";
    this.height = height;
    this.width = width;
  }
  sayName() {
    console.log("Hi, I am a ", this.name + ".");
  }
  get area() {
    return this.height \* this.width;
  }
  set area(value) {
    this._area = value;
  }
}

class Square extends Rectangle {
  constructor(length) {
    this.height; // ReferenceError, super должен быть вызван первым!

    // Здесь вызывается конструктор родительского класса с длинами,
    // указанными для ширины и высоты класса Rectangle
    super(length, length);

    // Примечание: в производных классах super() необходимо вызывать, прежде чем
    // использовать 'this'. Если этого не сделать, произойдет ошибка ReferenceError.
    this.name = "Square";
  }
}
```

### Вызов статических методов через super

Вы также можете вызывать super для статических методов.

```js
class Rectangle {
  static logNbSides() {
    return "У меня 4 стороны";
  }
}

class Square extends Rectangle {
  static logDescription() {
    return super.logNbSides() + ", равные между собой";
  }
}
Square.logDescription(); // 'У меня 4 стороны, равные между собой'
```

### Удаление свойств через super вызывает ошибку

Вы не можете использовать оператор delete и `super.prop` или `super[expr]` для удаления свойств родительского класса, он выдаст: `ReferenceError`.

```js
class Base {
  constructor() {}
  foo() {}
}
class Derived extends Base {
  constructor() {}
  delete() {
    delete super.foo; // это плохо
  }
}

new Derived().delete(); // ReferenceError: invalid delete involving 'super'.
```

### `super.prop` не может переопределять свойства, защищённые от записи

При определении незаписываемых свойств с помощью, например, `Object.defineProperty`, `super` не может перезаписать значение свойства.

```js
class X {
  constructor() {
    Object.defineProperty(this, "prop", {
      configurable: true,
      writable: false,
      value: 1,
    });
  }
}

class Y extends X {
  constructor() {
    super();
  }
  foo() {
    super.prop = 2; // Невозможно перезаписать значение.
  }
}

var y = new Y();
y.foo(); // TypeError: "prop" доступен только для чтения
console.log(y.prop); // 1
```

### Использование `super.prop` в объектных литералах

Super также можно использовать в объекте инициализатора / литерала. В этом примере метод определяют два объекта. Во втором объекте `super` вызывает метод первого объекта. Это работает благодаря `Object.setPrototypeOf()`, с помощью которого мы можем установить прототип для `obj2` в `obj1`, так что `super` может найти `method1` в `obj1`.

```js
var obj1 = {
  method1() {
    console.log("method 1");
  },
};

var obj2 = {
  method2() {
    super.method1();
  },
};

Object.setPrototypeOf(obj2, obj1);
obj2.method2(); // выведет "method 1"
```

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

| Specification |
| --- |
| ECMAScript Language Specification # sec-super-keyword |

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

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

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

* Классы


Инициализация объектов - JavaScript

Инициализация объектов
======================

Объекты могут быть инициализированы с помощью `new Object()`, `Object.create()` или *литеральной* (*инициирующей*) нотации. Инициализатор объекта это разделённый запятыми список ноль или более пар имён свойств и ассоциируемых с ними значений, заключённых в фигурные скобки (`{}`).

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

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

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

var o = {
  property: function ([parameters]) {},
  get property() {},
  set property(value) {},
};
```

### Новая нотация в ECMAScript 2015

Пожалуйста, просмотрите таблицу поддержки этих нотаций. В неподдерживаемом окружении, эти нотации приведут к синтаксической ошибке.

```js
// Сокращение имён свойств (ES2015)
var a = "foo",
  b = 42,
  c = {};
var o = { a, b, c };

// Сокращение имён методов (ES2015)
var o = {
  property([parameters]) {},
};

// Вычисление имён свойств (ES2015)
var prop = "foo";
var o = {
  [prop]: "hey",
  ["b" + "ar"]: "there",
};
```

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

Инициализатор объекта это выражение, которое описывает инициализацию `Object`. Объекты состоят из *свойств*, которые используются для описания объекта. Значения свойств объектов могут содержать как примитивные типы данных, так и другие объекты.

### Создание объектов

Пустой объект без свойств может быть создан следующим образом:

```js
var object = {};
```

Однако, преимущество *литеральной* или *инициирующей* нотации это возможность быстро создавать объекты со свойствами внутри фигурных скобок. Создаётся простой список пар `ключ: значение`, разделённых запятой. Следующий код создаёт объект с тремя парами значений и ключи это `"foo"`, `"age"` и `"baz"`. Значения этих ключей строка `"bar"`, число `42` и другой объект.

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

### Доступность свойств

После того, как создали объект, вы, вероятно, захотите прочитать или изменить его. Свойства объектов могут быть получены при помощи точечной нотации или квадратных скобок. Смотрите property accessors для детальной информации.

```js
object.foo; // "bar"
object["age"]; // 42

object.foo = "baz";
```

### Определение свойств

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

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

var o = {
  a: a,
  b: b,
  c: c,
};
```

С ECMAScript 2015 появилась короткая нотация, способная достичь того же:

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

// Сокращение имён свойств (ES2015)
var o = { a, b, c };

// Иначе говоря,
console.log(o.a === { a }.a); // true
```

#### Повторение имён свойств

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

```js
var a = { x: 1, x: 2 };
console.log(a); // {x: 2}
```

В строгом режиме ECMAScript 5, повторение имён свойств будет воспринято как `SyntaxError`. С введением вычисляемых имён свойств и появлением возможности создавать дубликаты во время выполнения кода, ECMAScript 2015 убрал это ограничение.

```js
function haveES2015DuplicatePropertySemantics() {
  "use strict";
  try {
    ({ prop: 1, prop: 2 });

    // Не будет ошибки, повторение имён доступно в строгом режиме
    return true;
  } catch (e) {
    // Будет ошибка, дубликаты запрещены в строгом режиме
    return false;
  }
}
```

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

Свойство объекта также может ссылаться на function, getter или setter.

```js
var o = {
  property: function ([parameters]) {},
  get property() {},
  set property(value) {},
};
```

В ECMAScript 2015, доступна короткая нотация, поэтому слово "function" более не обязательно.

```js
// Сокращение имён методов (ES2015)
var o = {
  property([parameters]) {},
  \*generator() {},
};
```

В ECMAScript 2015 есть способ кратко объявить свойства, чьими значениями являются генераторы функций:

```js
var o = {
  \*generator() {
    ...........
  }
};
```

Что эквивалентно следующей ES5-подобной нотации (но отметьте, что ECMAScript 5 не содержит генераторов):

```js
var o = {
  generator: function\* () {
    ...........
  }
};
```

Для большей информации и примеров смотри method definitions.

### Вычисляемые имена свойств

Начиная с ECMAScript 2015, синтаксис объявления объектов также поддерживает вычисляемые имена свойств. Это позволяет добавлять в скобки `[]` выражение, которое будет вычислено, как имя свойства. Это похоже на скобочную нотацию синтаксиса property accessor, которую вы, вероятно, уже использовали, чтобы прочитать и задать свойство. Теперь можно использовать аналогичный способ с литеральными объектами:

```js
// Вычисляемое имя свойства (ES2015)
var i = 0;
var a = {
  ["foo" + ++i]: i,
  ["foo" + ++i]: i,
  ["foo" + ++i]: i,
};

console.log(a.foo1); // 1
console.log(a.foo2); // 2
console.log(a.foo3); // 3

var param = "size";
var config = {
  [param]: 12,
  ["mobile" + param.charAt(0).toUpperCase() + param.slice(1)]: 4,
};

console.log(config); // {size: 12, mobileSize: 4}
```

### Spread-свойства

Rest/Spread свойство ECMAScript предлагает (stage 3) добавлять spread свойства в литеральную нотацию. Оно копирует собственные перечисляемые свойства из представленного объекта в новый.

Поверхностное копирование (исключая prototype) или слияние объектов теперь возможно с помощью более короткого синтаксиса, чем `Object.assign()`.

```js
var obj1 = { foo: "bar", x: 42 };
var obj2 = { foo: "baz", y: 13 };

var clonedObj = { ...obj1 };
// Объект { foo: "bar", x: 42 }

var mergedObj = { ...obj1, ...obj2 };
// Объект { foo: "baz", x: 42, y: 13 }
```

Заметьте, что `Object.assign()` вызывает setters, тогда как оператор spread нет.

### Изменение Prototype

Объявление свойства в виде `__proto__: value` или `"__proto__": value` не создаст свойства с именем `__proto__`. Вместо этого, если предоставляемое значение объект или `null`, оно заменит `[[Prototype]]` создаваемого объекта на это значение. (Если значение не объект или null, объект не изменится.)

```js
var obj1 = {};
assert(Object.getPrototypeOf(obj1) === Object.prototype);

var obj2 = { \_\_proto\_\_: null };
assert(Object.getPrototypeOf(obj2) === null);

var protoObj = {};
var obj3 = { \_\_proto\_\_: protoObj };
assert(Object.getPrototypeOf(obj3) === protoObj);

var obj4 = { \_\_proto\_\_: "not an object or null" };
assert(Object.getPrototypeOf(obj4) === Object.prototype);
assert(!obj4.hasOwnProperty("\_\_proto\_\_"));
```

Только одно изменение prototype разрешено через литеральное объявление объекта: несколько изменений prototype вызовут синтаксическую ошибку.

Объявление свойства не через "двоеточие" не изменит значения prototype: это описание будет выглядеть идентично такому же объявлению свойства с использованием любого другого имени.

```js
var __proto__ = "variable";

var obj1 = { __proto__ };
assert(Object.getPrototypeOf(obj1) === Object.prototype);
assert(obj1.hasOwnProperty("\_\_proto\_\_"));
assert(obj1.__proto__ === "variable");

var obj2 = {
  \_\_proto\_\_() {
    return "hello";
  },
};
assert(obj2.\_\_proto\_\_() === "hello");

var obj3 = { ["\_\_prot" + "o\_\_"]: 17 };
assert(obj3.__proto__ === 17);
```

Литеральная нотация vs JSON
---------------------------

Литеральная нотация не то же самое, что и **J**ava**S**cript **O**bject **N**otation (JSON). Хотя они и выглядят аналогично, существует разница между ними:

* JSON позволяет объявление свойств *только* с помощью синтаксиса `"property": value`. Имя свойства должно быть заключено в двойные кавычки и объявление не может быть сокращено.
* В JSON значения могут быть только строками, числами, массивами, `true`, `false`, `null` или другими (JSON) объектами.
* Значения-функции (смотри "Методы" выше) не могут быть присвоены свойствам в JSON.
* Объект вида `Date` будет строкой после `JSON.parse()`.
* `JSON.parse()` отклонит вычисляемые имена свойств и вернёт ошибку.
Спецификации
------------

| Specification |
| --- |
| ECMAScript Language Specification # sec-object-initializer |

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

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

See also
--------

* Property accessors
* `get` / `set`
* Method definitions
* Lexical grammar


Оператор группировки - JavaScript

Оператор группировки
====================

Оператор группировки `( )` контролирует порядок выполнения в выражениях.

Интерактивный пример
--------------------

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

 ( )
```

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

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

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

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

```js
let a = 1;
let b = 2;
let c = 3;

// обычный порядок
a + b \* c; // 7
// выполнится так
a + (b \* c); // 7

// теперь переопределим порядок
// сложение будет до умножения
(a + b) \* c; // 9

// что эквивалентно следующему
a \* c + b \* c; // 9
```

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

| Specification |
| --- |
| ECMAScript Language Specification # sec-grouping-operator |

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

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

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

* Приоритет операторов
* `delete`
* `typeof`


Логическое нулевое присваивание (??=) - JavaScript

Логическое нулевое присваивание (??=)
=====================================

Оператор логического нулевого присваивания (`x ??= y`) присваивает значение переменной `x`, если она содержит похожее на null значение (en-US) (`null` или `undefined`).

Интерактивный пример
--------------------

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

```js
expr1 ??= expr2;
```

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

### Сокращённое вычисление

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

`(выражение без null или undefined) ?? следующее выражение` останавливает вычисление на левом выражении, если его результат отличен от `null` или `undefined`.

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

Логическое нулевое присваивание также поддерживает сокращённое вычисление, поэтому `x ??= y` по сути то же самое, что и выражение ниже:

```js
x ?? (x = y);
```

В отличие от следующего примера, где операция присваивания произойдёт вне зависимости от результата вычисления:

```js
x = x ?? y;
```

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

### Использование логического нулевого присваивания

```js
function config(options) {
  options.duration ??= 100;
  options.speed ??= 25;
  return options;
}

config({ duration: 125 }); // { duration: 125, speed: 25 }
config({}); // { duration: 100, speed: 25 }
```

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

| Specification |
| --- |
| ECMAScript Language Specification # sec-assignment-operators |

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

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

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

* Оператор нулевого слияния (`??`)
* Похожее на null значение (en-US)
* Истиноподобное значение
* Ложноподобное значение


Присваивание логического И (&&=) - JavaScript

Присваивание логического И (&&=)
================================

Оператор присваивания логического И (`x &&= y`) присваивает значение переменной `x` только в случае, если её текущее значение истинноподобно.

Интерактивный пример
--------------------

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

```js
expr1 &&= expr2;
```

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

### Сокращённое вычисление

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

`(ложноподобное выражение) && следующее выражение` — вычисление останавливается на ложноподобном выражении;

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

Оператор присваивания логического И также поддерживает сокращённое вычисление, поэтому `x &&= y` по сути то же самое, что и выражение ниже:

```js
x && (x = y);
```

В отличие от следующего примера, где операция присваивания произойдёт вне зависимости от результата вычисления:

```js
x = x && y;
```

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

### Использование оператора присваивания логического И

```js
let x = 0;
let y = 1;

x &&= 0; // 0
x &&= 1; // 0
y &&= 1; // 1
y &&= 0; // 0
```

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

| Specification |
| --- |
| ECMAScript Language Specification # sec-assignment-operators |

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

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

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

* Логическое И (&&)
* Оператор нулевого слияния (`??`)
* Присваивание побитового И (`&=`) (en-US)
* Истиноподобное значение
* Ложноподобное значение


Логическое И (&&) - JavaScript

Логическое И (&&)
=================

Логический оператор И (`&&`) (конъюнкция) для набора операндов со значением типа `Boolean` будет `true` только в случае, если все операнды содержат значение `true`. В противном случае это будет `false`.

В целом, оператор вернёт значение первого ложноподобного операнда при вычислении, либо значение последнего операнда, если все операнды оказались истиноподобными.

Интерактивный пример
--------------------

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

```js
expr1 && expr2;
```

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

Логическое И (`&&`) вычисляет операнды слева направо, возвращая сразу значение первого попавшего ложноподобного операнда; если все значения истиноподобны, возвращается значение последнего операнда.

Если значение может быть преобразовано в `true`, то оно рассматривается как истиноподобное (truthy). Если же значение может быть преобразовано в `false`, то оно называется ложноподобным (falsy).

Примеры выражений, которые могут быть преобразованы в `false`:

* `false`;
* `null`;
* `NaN`;
* `0`;
* пустая строка (`""`, `''`, ````);
* `undefined`.

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

```js
result = "" && "foo"; // result is assigned "" (empty string)
result = 2 && 0; // result is assigned 0
result = "foo" && 4; // result is assigned 4
```

 Несмотря на то, что оператор `&&` может использоваться с операндами, не содержащие логических значений, он всё равно останется булевым оператором, поскольку его возвращаемое значение всегда можно преобразовать в булевый примитив.
 Чтобы явно преобразовать возвращаемое значение этого оператора (или вообще любое выражение) в соответствующее значение булевого типа, используйте двойной `оператор НЕ` или конструктор `Boolean` (en-US).

### Сокращённое вычисление

 Оператор логического И вычисляет выражение по сокращённой схеме.
 Каждый операнд приводится к булевому значению, если результат одного преобразования оказывается `false`, тогда оператор И останавливает дальнейшее вычисление выражения и возвращает исходное значение этого ложноподобного операнда. Поэтому оставшиеся операнды **не** будут вычислены.

В качестве примера рассмотрим следующий псевдокод.
```

(ложноподобное выражение) && следующее выражение
```

 Поскольку первый операнд `(ложноподобное выражение)` имеет ложное значение, то `следующее выражение` **никогда не будет вычислено**.
 Если `следующее выражение` содержало функцию, то она бы никогда не была вызвана.
 Посмотрите пример ниже:

```js
function A() {
  console.log("вызвана функция A");
  return false;
}
function B() {
  console.log("вызвана функция B");
  return true;
}

console.log(A() && B());
// В результате вызова функции A, в консоли будет выведено "вызвана функция A",
// а оператор && вычислится как false (функция A возвращает false), поэтому далее в консоли появится false;
// вследствие этого оператор И прекратит вычисление и проигнорирует функцию B
```

### Приоритет операторов

Оператор И имеет более высокий приоритет, чем оператор ИЛИ, поэтому оператор `&&` выполнится раньше оператора `||` (см. приоритет операторов).

```js
false || (true && true); // вернёт true
true && (false || false); // вернёт false
2 == 3 || (4 < 0 && 1 == 1); // вернёт false
```

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

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

В следующем коде показаны примеры использования оператора `&&` (логическое И).

```js
a1 = true && true; // t && t вернёт true
a2 = true && false; // t && f вернёт false
a3 = false && true; // f && t вернёт false
a4 = false && 3 == 4; // f && f вернёт false
a5 = "Cat" && "Dog"; // t && t вернёт "Dog"
a6 = false && "Cat"; // f && t вернёт false
a7 = "Cat" && false; // t && f вернёт false
a8 = "" && false; // f && f вернёт ""
a9 = false && ""; // f && f вернёт false
```

### Правила преобразования булевых значений

#### Конвертация И к ИЛИ

Следующая операция с **булевыми значениями**:

```js
bCondition1 && bCondition2;
```

всегда эквивалентна:

```js
!(!bCondition1 || !bCondition2);
```

#### Конвертация ИЛИ к И

Следующая операция с **булевыми значениями**:

```js
bCondition1 || bCondition2;
```

всегда эквивалентна:

```js
!(!bCondition1 && !bCondition2);
```

### Удаление вложенных круглых скобок

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

Следующая составная операция с **булевыми значениями**:

```js
bCondition1 || (bCondition2 && bCondition3);
```

это то же самое, что и:

```js
bCondition1 || (bCondition2 && bCondition3);
```

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

| Specification |
| --- |
| ECMAScript Language Specification # prod-LogicalANDExpression |

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

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

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

* `Boolean`
* Truthy
* Falsy


instanceof - JavaScript

instanceof
==========

Оператор **`instanceof`** проверяет, принадлежит ли объект к определённому классу. Другими словами, `object instanceof constructor` проверяет, присутствует ли объект `constructor.prototype` в цепочке прототипов `object`.

Интерактивный пример
--------------------

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

object instanceof constructor
```

### Параметры

`object`

Проверяемый объект.

`constructor`

Функция-конструктор, на которую идёт проверка.

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

Оператор `instanceof` проверяет, присутствует ли объект `constructor.prototype` в цепочке прототипов `object`.

```js
// объявляем конструкторы
function C() {}
function D() {}

var o = new C();

// true, так как: Object.getPrototypeOf(o) === C.prototype
o instanceof C;

// false, так как D.prototype не присутствует в цепочке прототипов o
o instanceof D;

o instanceof Object; // true, так как:
C.prototype instanceof Object; // true

C.prototype = {};
var o2 = new C();

o2 instanceof C; // true

// false, так как C.prototype отсутствует в цепочке прототипов o
o instanceof C;

D.prototype = new C(); // add C to [[Prototype]] linkage of D
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true, так как C.prototype теперь присутствует в цепочке прототипов o3
```

Обратите внимание: результат оператора `instanceof` зависит от свойства `constructor.prototype`, поэтому результат оператора может поменяться после изменения этого свойства. Также результат может поменяться после изменения прототипа `object` (или цепочки прототипов) с помощью `Object.setPrototypeOf` или нестандартного свойства `__proto__`.

### `instanceof` и множественные контексты (например, фреймы или окна)

Различные контексты имеют разные среды выполнения. Это означает, что они имеют различные built-ins (разный глобальный объект, различные конструкторы и т.д.). Это может давать неожиданные результаты. Например, `[] instanceof window.frames[0].Array` вернёт `false`, потому что `Array.prototype !== window.frames[0].Array` а массив наследуется от `Array`.

Это может казаться несущественной проблемой сначала, но при работе с несколькими фреймами или окнами, и передачи объектов из одного контекста в другой с помощью функций, это может стать серьёзной проблемой. С другой стороны, безопасно проверить, является ли некоторый объект массивом можно используя `Array.isArray(myObj)`.

Например, для проверки того, что Node является SVGElement (en-US) в разных контекстах можно использовать `myNode instanceof myNode.ownerDocument.defaultView.SVGElement`.

**Примечание:** Использование XPCOM `instanceof` в коде имеет специальный эффект: `obj instanceof xpcomInterface` (например `Components.interfaces.nsIFile`) вызывает `obj.QueryInterface(xpcomInterface)` и возвращает `true` если проверка на QueryInterface прошла успешно. Побочным эффектом этого вызова является то, что можно использовать свойства *`xpcomInterface`* на `obj` после успешной проверки с помощью `instanceof`. В отличии от стандартных глобальных JavaScript типов, проверка `obj instanceof xpcomInterface` работает как ожидается, даже если `obj` относится к другому контексту.

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

### Показывает, что `String` и `Date` имеют тип `Object` и граничные случаи

Следующий код использует `instanceof`, чтобы показать что объекты `String` и `Date` также имеют тип `Object` (они являются наследниками `Object`).

Однако, объекты, созданные с помощью литералов, являются исключениями — хотя их prototype равен `undefined`, выражение `instanceof Object` возвращает `true`.

```js
var simpleStr = "Это обычная строка";
var myString = new String();
var newStr = new String("Строка, созданная с помощью конструктора");
var myDate = new Date();
var myObj = {};

simpleStr instanceof String; // возвращает false, проверяет цепочку прототипов
myString instanceof String; // возвращает true
newStr instanceof String; // возвращает true
myString instanceof Object; // возвращает true

myObj instanceof Object; // возвращает true, несмотря на прототип, равный undefined
({}) instanceof Object; // возвращает true, аналогично предыдущей строчке

myString instanceof Date; // возвращает false

myDate instanceof Date; // возвращает true
myDate instanceof Object; // возвращает true
myDate instanceof String; // возвращает false
```

### Показывает, что `mycar` имеет тип `Car` и тип `Object`

Следующий код создаёт тип `Car` и экземпляр этого типа, `mycar`. Оператор `instanceof` показывает, что объект `mycar` имеет тип `Car` и тип `Object`.

```js
function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}
var mycar = new Car("Honda", "Accord", 1998);
var a = mycar instanceof Car; // возвращает true
var b = mycar instanceof Object; // возвращает true
```

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

| Specification |
| --- |
| ECMAScript Language Specification # sec-relational-operators |

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

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

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

* `typeof`
* `Symbol.hasInstance`


Присваивание логического ИЛИ (

Присваивание логического ИЛИ (||=)
==================================

Оператор присваивания логического ИЛИ (`x ||= y`) присваивает значение переменной `x` только в случае, если её текущее значение ложноподобно.

Интерактивный пример
--------------------

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

```js
expr1 ||= expr2;
```

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

### Сокращённое вычисление

Оператор логического ИЛИ работает следующим образом:

```js
x || y;
// возвращает x, если x истинноподобен
// возвращает y, если x не истинноподобен
```

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

Оператор присваивания логического ИЛИ также поддерживает сокращённое вычисление, т.е. выполнит операцию присваивания только при вычислении правого выражения. Проще говоря, `x ||= y` эквивалентно следующему коду:

```js
x || (x = y);
```

В отличие от следующего примера, где операция присваивания произойдёт в любом случае:

```js
x = x || y;
```

Обратите внимание, что математические и побитовые операторы присваивания работают по-разному.

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

### Определение значения по умолчанию

Если в элементе с идентификатором "lyrics" нет содержимого, то следующее выражение вставит в него надпись:

```js
document.getElementById("lyrics").textContent ||= "Нет слов.";
```

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

Примечание: обратите внимание на значение в левом операнде. Если это пустая строка (ложноподобное значение), то должно использовать оператор `||=`, в противном случае — оператор `??=` (если ожидается получение значения `null` или `undefined`).

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

| Specification |
| --- |
| ECMAScript Language Specification # sec-assignment-operators |

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

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

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

* Логическое ИЛИ(||)
* Оператор нулевого слияния (`??`)
* Оператор присваивания побитового ИЛИ (`|=`) (en-US)
* Истиноподобное значение
* Ложноподобное значение


typeof - JavaScript

typeof
======

Оператор **`typeof`** возвращает строку, указывающую тип операнда.

Интерактивный пример
--------------------

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

Операнд следует за оператором `typeof`:
```

typeof operand
```

### Параметры

`operand` является выражением, представляющим объект или примитив, тип которого должен быть возвращён.

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

В следующей таблице приведены возможные возвращаемые значения `typeof`. Дополнительная информация о типах и примитивах находится на странице структуры данных JavaScript.

| Type | Result |
| --- | --- |
| Undefined | `"undefined"` |
| Null | `"object"` (смотрите ниже) |
| Boolean | `"boolean"` |
| Number | `"number"` |
| String | `"string"` |
| Symbol (новый тип из ECMAScript 2015) | `"symbol"` |
| Host object (определено JS окружением) | *Зависит от реализации* |
| Function object (реализует [[Call]] в терминах ECMA-262) | `"function"` |
| Любой другой тип | `"object"` |

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

```js
// Числа
typeof 37 === "number";
typeof 3.14 === "number";
typeof 42 === "number";
typeof Math.LN2 === "number";
typeof Infinity === "number";
typeof NaN === "number"; // несмотря на то, что это "Not-A-Number" (не число)
typeof Number(1) === "number"; // никогда не используйте эту запись!

// Строки
typeof "" === "string";
typeof "bla" === "string";
typeof "1" === "string"; // обратите внимание, что число внутри строки всё равно имеет тип строки
typeof typeof 1 === "string"; // typeof всегда вернёт в этом случае строку
typeof String("abc") === "string"; // никогда не используйте эту запись!

// Booleans
typeof true === "boolean";
typeof false === "boolean";
typeof Boolean(true) === "boolean"; // никогда не используйте эту запись!

// Символы
typeof Symbol() === "symbol";
typeof Symbol("foo") === "symbol";
typeof Symbol.iterator === "symbol";

// Undefined
typeof undefined === "undefined";
typeof declaredButUndefinedVariable === "undefined";
typeof undeclaredVariable === "undefined";

// Объекты
typeof { a: 1 } === "object";

// используйте Array.isArray или Object.prototype.toString.call
// чтобы различить обычные объекты и массивы
typeof [1, 2, 4] === "object";

typeof new Date() === "object";

// То что ниже приводит к ошибкам и проблемам. Не используйте!
typeof new Boolean(true) === "object";
typeof new Number(1) === "object";
typeof new String("abc") === "object";

// Функции
typeof function () {} === "function";
typeof class C {} === "function";
typeof Math.sin === "function";
```

### `null`

```js
// Это было определено с рождения JavaScript
typeof null === "object";
```

В первой реализации JavaScript значения были представлены парой тип тега и значение. Тип тега для объектов равнялся 0. `null` был представлен как нулевой указатель (0x00 в большинстве платформ). Следовательно, тип тега для `null` равнялся нулю, поэтому возвращаемое значение `typeof` является фиктивным. (подробнее)

Исправление было предложено в ECMAScript (через отключение), но было отклонено. Это привело бы к тому, что `typeof null === 'null'`.

### Использование оператора `new`

```js
// Все функции-конструкторы, созданные с помощью 'new', будут иметь тип 'object'
var str = new String("String");
var num = new Number(100);

typeof str; // Вернёт 'object'
typeof num; // Вернёт 'object'

// Но существует исключение для конструктора Function

var func = new Function();

typeof func; // Вернёт 'function'
```

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

Вызываемые регулярные выражения были нестандартным дополнением в некоторых браузерах.

```js
typeof /s/ === "function"; // Chrome 1-12 Не соответствует ECMAScript 5.1
typeof /s/ === "object"; // Firefox 5+ Соответствует ECMAScript 5.1
```

### Ошибки, связанные с временными мёртвыми зонами

До ECMAScript 2015, гарантировалось, что оператор `typeof` вернёт строку для любого операнда, с которым он был вызван. Это изменилось после добавления не поднимающихся объявлений `let` and `const` с блочной областью видимости. Теперь, если переменные объявлены с помощью `let` и `const`, и для них вызывается `typeof` в блоке объявления переменных, но до объявления, то выбрасывается `ReferenceError`. Поведение отличается от необъявленных переменных, для которых `typeof` вернёт 'undefined'. Переменные с блочной областью видимости находятся в "временной мёртвой зоне", которая длится от начала блока до момента объявления переменных. В этой зоне попытка доступа к переменным выбрасывает исключение.

```js
typeof undeclaredVariable === "undefined";
typeof newLetVariable;
let newLetVariable; // ReferenceError
typeof newConstVariable;
const newConstVariable = "hello"; // ReferenceError
```

### Исключения

Во всех текущих браузерах существует нестандартный host-объект `document.all`, который имеет тип Undefined.

```js
typeof document.all === "undefined";
```

Хотя спецификация разрешает собственные имена типов для нестандартных экзотических объектов, требуется чтобы эти имена отличались от предопределённых. Ситуация, когда `document.all` имеет тип `undefined` должна рассматриваться как исключительное нарушение правил.

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

| Specification |
| --- |
| ECMAScript Language Specification # sec-typeof-operator |

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

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

IE-специфичные замечания
------------------------

В IE 6, 7 и 8 многие host-объекты являются объектами, но не функциями. Например:

```js
typeof alert === "object";
```

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

* `instanceof`
* Why typeof is no longer "safe"


Сложение с присваиванием (+=) - JavaScript

Сложение с присваиванием (+=)
=============================

Оператор сложения с присваиванием (`+=`) добавляет значение правого операнда к переменной и присваивает переменной результат. Типы двух операндов определяют поведение оператора сложения с присваиванием. Добавление или конкатенация возможны.

Интерактивный пример
--------------------

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

Оператор: x += y
Значение: x  = x + y
```

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

### Использование сложения с присваиванием

```js
// Assuming the following variables
// foo = 'foo'
// bar = 5
// baz = true

// Number + Number -> addition
bar += 2; // 7

// Boolean + Number -> addition
baz += 1; // 2

// Boolean + Boolean -> addition
baz += false; // 1

// Number + String -> concatenation
bar += "foo"; // "5foo"

// String + Boolean -> concatenation
foo += false; // "foofalse"

// String + String -> concatenation
foo += "bar"; // "foobar"
```

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

| Specification |
| --- |
| ECMAScript Language Specification # sec-assignment-operators |

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

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

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

* Assignment operators in the JS guide
* Оператор сложения


Оператор опциональной последовательности - JavaScript

Оператор опциональной последовательности
========================================

Оператор **опциональной последовательности** **`?.`** позволяет получить значение свойства, находящегося на любом уровне вложенности в цепочке связанных между собой объектов, без необходимости проверять каждое из промежуточных свойств в ней на существование. `?.` работает подобно оператору `.`, за исключением того, что не выбрасывает исключение, если объект, к свойству или методу которого идёт обращение, равен `null` или `undefined`. В этих случаях он возвращает `undefined`.

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

Интерактивный пример
--------------------

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

```js
obj?.prop;
obj?.[expr];
arr?.[index];
func?.(args);
```

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

Оператор опциональной последовательности предоставляет способ упростить доступ к значениям в цепочке объектов, когда возможно, что какое-то свойство (или метод) в ней равно `undefined` или `null`.

Для примера, создадим объект `obj`, имеющий вложенную структуру. Без оператора опциональной последовательности поиск глубоко расположенных подсвойств требует проверки всех промежуточных свойств на существование, например:

```js
let nestedProp = obj.first && obj.first.second;
```

Если обращаться к `obj.first.second` без проверки `obj.first`, то, если свойство `obj.first` равно `null` или `undefined`, выбросится исключение `TypeError`.

Однако, с оператором опциональной последовательности (`?.`) не требуется явно проверять ссылку на `obj.first` перед обращением к `obj.first.second`:

```js
let nestedProp = obj.first?.second;
```

Если используется оператор `?.` вместо `.`, JavaScript знает о необходимости проверки `obj.first` перед обращением к `obj.first.second`. Если значение `obj.first` равно `null` или `undefined`, выполнение выражения автоматически прекращается и возвращается `undefined`.

Это эквивалентно следующему (кроме создания временной переменной):

```js
let temp = obj.first;
let nestedProp = temp === null || temp === undefined ? undefined : temp.second;
```

### Опциональная последовательность с вызовом функции

Вы можете использовать `?.`**,** когда необходимо вызвать метод, которого может не существовать. Это может быть полезно, например, при использовании API, в котором метод может быть недоступен из-за устаревания или не поддерживаемости устройством пользователя.

Использование `?.` с вызовом функции значит, что выполнение автоматически вернёт `undefined`, а не выбросит исключение, если метод не найден:

```js
let result = someInterface.customMethod?.();
```

**Примечание:** Для существующего свойства, не являющегося функцией, использование конструкции `x.y?.()` всё равно выбросит `TypeError` исключение (`x.y не является функцией`).

### Работа с колбэк-функциями и обработчиками событий

Если вы используете колбэк-функции или извлекаете методы объекта деструктурирующим присваиванием, Вы можете получить несуществующие значения, которые нельзя вызывать как функции до проверки на их существование. Используя оператор `?.`, вы можете избежать лишних проверок:

```js
// С использованием ES2019
function doSomething(onContent, onError) {
  try {
    // ... делаем что-то с данными
  } catch (err) {
    if (onError) {
      // проверяем, существует ли onError
      onError(err.message);
    }
  }
}
```

```js
// С использованием оператора опциональной последовательности
function doSomething(onContent, onError) {
  try {
    // ... делаем что-то с данными
  } catch (err) {
    onError?.(err.message); // не выбросит исключение, если onError равен undefined
  }
}
```

### Опциональные последовательности в выражениях

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

```js
let nestedProp = obj?.["prop" + "Name"];
```

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

### Базовый пример

В этом примере производится обращение к свойству `name` элемента с ключом `bar` объекта `Map`. Элемент с таким ключом отсутствует, но исключение выброшено не будет; `nameBar` равен `undefined`.

```js
let myMap = new Map();
myMap.set("foo", { name: "baz", desc: "inga" });

let nameBar = myMap.get("bar")?.name;
```

### Сокращённое выполнение

При использовании оператора опциональной последовательности в выражениях, где левая часть операнда равна `null` или `undefined`, выражение не будет выполнено. Например:

```js
let potentiallyNullObj = null;
let x = 0;
let prop = potentiallyNullObj?.[x++];

console.log(x); // 0, т.к. x не был инкрементирован
```

### Совместное использование операторов опциональной последовательности

Во вложенных объектах возможно использование оператора опциональной последовательности неограниченное количество раз:

```js
let customer = {
  name: "Carl",
  details: {
    age: 82,
    location: "Paradise Falls", // точный адрес неизвестен
  },
};
let customerCity = customer.details?.address?.city;

// … это также работает с вызовами функций
let duration = vacations.trip?.getTime?.();
```

### Использование с оператором ??

Оператор ?? может использоваться после опциональной последовательности для установления значения по умолчанию:

```js
let customer = {
  name: "Carl",
  details: { age: 82 },
};
const customerCity = customer?.city ?? "Unknown city";
console.log(customerCity); // Unknown city
```

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

| Specification |
| --- |
| ECMAScript Language Specification # prod-OptionalExpression |

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

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

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

* Github - Proposal-pipeline-operator
* TC39 proposals
* Nullish Coalescing Operator


Bitwise AND (&) - JavaScript

Bitwise AND (&)
===============

Побитовый оператор И (`&`) возвращает `1` в каждой битовой позиции, для которой соответствующие биты обоих операндов равны `1`.

Интерактивный пример
--------------------

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

a & b
```

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

Операнды преобразуются в 32-битные целые числа и выражаются серией битов (нулей and единиц). Числа с более чем 32 битами отбрасывают старшие разряды. Например, следующее целое число с более чем 32 битами будет преобразовано в 32-битное целое:
```

До: 11100110111110100000000000000110000000000001
После:          10100000000000000110000000000001
```

Каждый бит в первом операнде связан с соответствующим битом во втором операнде:*первый бит - с первым*,*второй- со вторым*, и т.д.

Оператор применяется к каждой паре битов, и результат строится побитово.

Таблица истинности для оператора И:

| a | b | a И b |
| --- | --- | --- |
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |

```js
.    9 (base 10) = 00000000000000000000000000001001 (base 2)
    14 (base 10) = 00000000000000000000000000001110 (base 2)
                   --------------------------------
14 & 9 (base 10) = 00000000000000000000000000001000 (base 2) = 8 (base 10)
```

Побитовое И для любого числа `x` с `0` даёт `0`.

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

### Использование побитового И

```js
// 5: 00000000000000000000000000000101
// 2: 00000000000000000000000000000010
5 & 2; // 0
```

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

| Specification |
| --- |
| ECMAScript Language Specification # prod-BitwiseANDExpression |

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

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

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

* Bitwise operators in the JS guide
* Bitwise AND assignment operator (en-US)