es6
This commit is contained in:
parent
43dfa400c1
commit
413e552c29
5 changed files with 188 additions and 112 deletions
|
@ -1,10 +1,5 @@
|
|||
# ES-2015 сейчас
|
||||
|
||||
[smart header="Этот раздел -- в активной разработке"]
|
||||
Стандарт ES-2015 недавно был принят окончательно, и этот раздел находится в ежедневной разработке.
|
||||
|
||||
[/smart]
|
||||
|
||||
[Стандарт ES-2015](http://www.ecma-international.org/publications/standards/Ecma-262.htm) был принят в июне 2015. Пока что большинство браузеров реализуют его частично, текущее состояние реализации различных возможностей можно посмотреть здесь: [](https://kangax.github.io/compat-table/es6/).
|
||||
|
||||
Когда стандарт будет более-менее поддерживаться во всех браузерах, то весь учебник будет обновлён в соответствии с ним. Пока же, как центральное место для "сбора" современных фич JavaScript, создан этот раздел.
|
||||
|
@ -68,7 +63,7 @@
|
|||
|
||||
Это означает, что при запуске примеров в браузере, который их не поддерживает, будет ошибка. Это не означает, что пример неправильный! Просто пока нет поддержки...
|
||||
|
||||
Рекомендуется [Chrome Canary](https://www.google.com/chrome/browser/canary.html), Edge или [Firefox Developer Edition](https://www.mozilla.org/en-US/firefox/channel/#developer).
|
||||
Рекомендуется [Chrome Canary](https://www.google.com/chrome/browser/canary.html), Edge или [Firefox Developer Edition](https://www.mozilla.org/en-US/firefox/channel/#developer), большинство примеров в них работает.
|
||||
|
||||
Впрочем, если пример в браузере не работает (обычно проявляется как ошибка синтаксиса) -- почти все примеры вы можете запустить его при помощи Babel, на странице [Babel: try it out](https://babeljs.io/repl/). Там же увидите и преобразованный код.
|
||||
|
||||
|
@ -78,10 +73,3 @@
|
|||
|
||||
Итак, поехали!
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -9,12 +9,12 @@ let a = 5;
|
|||
|
||||
## let
|
||||
|
||||
У объявлений `let` три основных отличия от `var`:
|
||||
У объявлений переменной через `let` есть три основных отличия от `var`:
|
||||
|
||||
<ol>
|
||||
<li>**Область видимости переменной `let` -- блок `{...}`.**
|
||||
|
||||
Как мы помним, переменная, объявленная через `var`, видна везде в функции. В старом стандарте минимальная "область видимости" -- функция.
|
||||
Как мы помним, переменная, объявленная через `var`, видна везде в функции.
|
||||
|
||||
Переменная, объявленная через `let`, видна только в рамках блока `{...}`, в котором объявлена.
|
||||
|
||||
|
@ -37,7 +37,9 @@ if (true) {
|
|||
alert(apples); // 10 (снаружи блока то же самое)
|
||||
```
|
||||
|
||||
То же самое с `let`:
|
||||
В примере выше `apples` -- одна переменная на весь код, которая модифицируется в `if`.
|
||||
|
||||
То же самое с `let` будет работать по-другому:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
@ -58,7 +60,25 @@ alert(apples); // 5 (снаружи блока значение не измен
|
|||
|
||||
Здесь, фактически, две независимые переменные `apples`, одна -- глобальная, вторая -- в блоке `if`.
|
||||
|
||||
Заметим, что если объявление `apples` в строке `(*)` закомментировать, то в последнем `alert` будет ошибка: переменная неопределена. Это потому что переменная `let` всегда видна именно в том блоке, где объявлена и не более.
|
||||
Заметим, что если объявление `let apples` в первой строке `(*)` удалить, то в последнем `alert` будет ошибка: переменная неопределена:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
'use strict';
|
||||
|
||||
if (true) {
|
||||
let apples = 10;
|
||||
|
||||
alert(apples); // 10 (внутри блока)
|
||||
}
|
||||
|
||||
*!*
|
||||
alert(apples); // ошибка!
|
||||
*/!*
|
||||
```
|
||||
|
||||
|
||||
Это потому что переменная `let` всегда видна именно в том блоке, где объявлена, и не более.
|
||||
|
||||
</li>
|
||||
<li>**Переменная `let` видна только после объявления.**
|
||||
|
@ -98,17 +118,16 @@ let x;
|
|||
let x; // ошибка: переменная x уже объявлена
|
||||
```
|
||||
|
||||
Это -- хоть и выглядит ограничением по сравнению с `var`, но на самом деле проблем не создаёт, так как область видимости ограничена блоком.
|
||||
|
||||
Например, два таких цикла совсем не конфликтуют:
|
||||
Это -- хоть и выглядит ограничением по сравнению с `var`, но на самом деле проблем не создаёт. Например, два таких цикла совсем не конфликтуют:
|
||||
```js
|
||||
//+ run
|
||||
'use strict';
|
||||
|
||||
// каждый цикл имеет свою переменную i
|
||||
for(let i = 0; i<10; i++) { /* … */ }
|
||||
for(let i = 0; i<10; i++) { /* … */ }
|
||||
|
||||
alert( i ); // ошибка, переменная не определена
|
||||
alert( i ); // ошибка: глобальной i нет
|
||||
```
|
||||
|
||||
При объявлении внутри цикла переменная `i` будет видна только в блоке цикла. Она не видна снаружи, поэтому будет ошибка в последнем `alert`.
|
||||
|
@ -117,7 +136,7 @@ alert( i ); // ошибка, переменная не определена
|
|||
</li>
|
||||
<li>**При использовании в цикле, для каждой итерации создаётся своя переменная.**
|
||||
|
||||
Переменная `var` -- одна на все итерации цикла (и видна после цикла):
|
||||
Переменная `var` -- одна на все итерации цикла и видна даже после цикла:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
@ -126,9 +145,9 @@ for(var i=0; i<10; i++) { /* … */ }
|
|||
alert(i); // 10
|
||||
```
|
||||
|
||||
С переменной `let` -- всё по-другому. Добавляется ещё одна область видимости: блок цикла.
|
||||
С переменной `let` -- всё по-другому.
|
||||
|
||||
Каждому блоку цикла соответствует своя, независимая, переменная `let`. Если внутри цикла объявляются функции, то в замыкании каждой будет та переменная, которая была при итерации.
|
||||
Каждому повторению цикла соответствует своя независимая переменная `let`. Если внутри цикла есть вложенные объявления функций, то в замыкании каждой будет та переменная, которая была при соответствующей итерации.
|
||||
|
||||
Это позволяет легко решить классическую проблему с замыканиями, описанную в задаче [](/task/make-army).
|
||||
|
||||
|
@ -183,7 +202,7 @@ apple = 10; // ошибка
|
|||
<ul>
|
||||
<li>Видны только после объявления и только в текущем блоке.</li>
|
||||
<li>Нельзя переобъявлять (в том же блоке).</li>
|
||||
<li>В цикле каждое значение `let` принадлежит конкретной итерации цикла (и видно в замыканиях).</li>
|
||||
<li>При объявлении переменной в цикле `for(let …)` -- она видна только в этом цикле. Причём каждой итерации соответствует своя переменная `let`.</li>
|
||||
</ul>
|
||||
|
||||
Переменная `const` -- это константа, в остальном -- как `let`.
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
# Деструктуризация
|
||||
|
||||
*Деструктуризация* (destructuring assignment) -- способ присвоить массив или объект сразу нескольким переменным.
|
||||
*Деструктуризация* (destructuring assignment) -- это особый синтаксис присваивания, при котором можно присвоить массив или объект сразу нескольким переменным, разбив его на части.
|
||||
|
||||
## Массив
|
||||
|
||||
|
@ -10,15 +10,33 @@
|
|||
```js
|
||||
'use strict';
|
||||
|
||||
let [firstName, lastName] = "Илья Кантор".split(" ");
|
||||
let [firstName, lastName] = ["Илья", "Кантор"];
|
||||
|
||||
alert(firstName); // Илья
|
||||
alert(lastName); // Кантор
|
||||
```
|
||||
|
||||
При таком присвоении первые два значения массива будут помещены в переменные, а последующие -- будут отброшены.
|
||||
При таком присвоении первое значение массива пойдёт в переменную `firstName`, второе -- в `lastName`, а последующие (если есть) -- будут отброшены.
|
||||
|
||||
Однако, можно добавить ещё один параметр, который получит "всё остальное", при помощи троеточия ("spread"):
|
||||
Ненужные элементы массива также можно отбросить, поставив лишнюю запятую:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
'use strict';
|
||||
|
||||
*!*
|
||||
// первый и второй элементы не нужны
|
||||
let [, , title] = "Юлий Цезарь Император Рима".split(" ");
|
||||
*/!*
|
||||
|
||||
alert(title); // Император
|
||||
```
|
||||
|
||||
В коде выше первый и второй элементы массива никуда не записались, они были отброшены. Как, впрочем, и все элементы после третьего.
|
||||
|
||||
### Оператор "spread"
|
||||
|
||||
Если мы хотим получить и последующие значения массива, но не уверены в их числе -- можно добавить ещё один параметр, который получит "всё остальное", при помощи оператора `"..."` ("spread", троеточие):
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
@ -33,17 +51,32 @@ alert(lastName); // Цезарь
|
|||
alert(rest); // Император,Рима (массив из 2х элементов)
|
||||
```
|
||||
|
||||
Значением `rest` будет массив из оставшихся элементов массива.
|
||||
Значением `rest` будет массив из оставшихся элементов массива. Вместо `rest` можно использовать и другое имя переменной, оператор здесь -- троеточие. Оно должно стоять только последним элементом в списке слева.
|
||||
|
||||
**Можно задать и значения по умолчанию, если массив почему-то оказался короче, чем ожидалось.**
|
||||
### Значения по умолчанию
|
||||
|
||||
Если значений в массиве меньше, чем переменных -- ошибки не будет, просто присвоится `undefined`:
|
||||
|
||||
Они задаются через знак `=`, например:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
'use strict';
|
||||
|
||||
*!*
|
||||
let [firstName, lastName] = [];
|
||||
*/!*
|
||||
|
||||
alert(firstName); // undefined
|
||||
```
|
||||
|
||||
Впрочем, как правило, в таких случаях задают значение по умолчанию. Для этого нужно после переменной использовать символ `=` со значением, например:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
'use strict';
|
||||
|
||||
*!*
|
||||
// значения по умолчанию
|
||||
let [firstName="Гость", lastName="Анонимный"] = [];
|
||||
*/!*
|
||||
|
||||
|
@ -51,7 +84,7 @@ alert(firstName); // Гость
|
|||
alert(lastName); // Анонимный
|
||||
```
|
||||
|
||||
В качестве значений по умолчанию можно использовать не только примитивы, но и выражения, содержащие вызовы функций:
|
||||
В качестве значений по умолчанию можно использовать не только примитивы, но и выражения, даже включающие в себя вызовы функций:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
@ -70,27 +103,18 @@ alert(firstName); // Вася
|
|||
alert(lastName); // 1436...-visitor
|
||||
```
|
||||
|
||||
Заметим, что вызов функции `defaultLastName` будет осуществлён только при необходимости, то есть если значения нет в массиве.
|
||||
|
||||
**Ненужные элементы массива можно отбросить, поставив лишнюю запятую:**
|
||||
|
||||
```js
|
||||
//+ run
|
||||
'use strict';
|
||||
|
||||
*!*
|
||||
// первый и второй элементы не нужны
|
||||
let [, , title] = "Юлий Цезарь Император Рима".split(" ");
|
||||
*/!*
|
||||
|
||||
alert(title); // Император
|
||||
```
|
||||
|
||||
В коде выше первый и второй элементы массива никуда не записались, они были отброшены. Как, впрочем, и все элементы после третьего.
|
||||
Заметим, что вызов функции `defaultLastName()` для генерации значения по умолчанию будет осуществлён только при необходимости, то есть если значения нет в массиве.
|
||||
|
||||
## Деструктуризация объекта
|
||||
|
||||
Деструктуризация может "мгновенно" разобрать объект по переменным.
|
||||
Деструктуризацию можно использовать и с объектами. При этом мы указываем, какие свойства в какие переменные должны "идти".
|
||||
|
||||
Базовый синтаксис:
|
||||
```js
|
||||
let {var1, var2} = {var1:…, var2…}
|
||||
```
|
||||
|
||||
Объект справа -- уже существующий, который мы хотим разбить на переменные. А слева -- список переменных, в которые нужно соответствующие свойства записать.
|
||||
|
||||
Например:
|
||||
|
||||
|
@ -98,35 +122,35 @@ alert(title); // Император
|
|||
//+ run
|
||||
'use strict';
|
||||
|
||||
let menuOptions = {
|
||||
let options = {
|
||||
title: "Меню",
|
||||
width: 100,
|
||||
height: 200
|
||||
};
|
||||
|
||||
*!*
|
||||
let {title, width, height} = menuOptions;
|
||||
let {title, width, height} = options;
|
||||
*/!*
|
||||
|
||||
alert(`${title} ${width} ${height}`); // Меню 100 200
|
||||
```
|
||||
|
||||
Как видно, свойства автоматически присваиваются соответствующим переменным.
|
||||
Как видно, свойства `options.title`, `options.width` и `options.height` автоматически присвоились соответствующим переменным.
|
||||
|
||||
Если хочется присвоить свойство объекта в переменную с другим именем, можно указать соответствие через двоеточие, вот так:
|
||||
Если хочется присвоить свойство объекта в переменную с другим именем, например, чтобы свойство `options.width` пошло в переменную `w`, то можно указать соответствие через двоеточие, вот так:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
'use strict';
|
||||
|
||||
let menuOptions = {
|
||||
let options = {
|
||||
title: "Меню",
|
||||
width: 100,
|
||||
height: 200
|
||||
};
|
||||
|
||||
*!*
|
||||
let {width: w, height: h, title} = menuOptions;
|
||||
let {width: w, height: h, title} = options;
|
||||
*/!*
|
||||
|
||||
alert(`${title} ${w} ${h}`); // Меню 100 200
|
||||
|
@ -140,12 +164,12 @@ alert(`${title} ${w} ${h}`); // Меню 100 200
|
|||
//+ run
|
||||
'use strict';
|
||||
|
||||
let menuOptions = {
|
||||
let options = {
|
||||
title: "Меню"
|
||||
};
|
||||
|
||||
*!*
|
||||
let {width=100, height=200, title} = menuOptions;
|
||||
let {width=100, height=200, title} = options;
|
||||
*/!*
|
||||
|
||||
alert(`${title} ${width} ${height}`); // Меню 100 200
|
||||
|
@ -158,33 +182,33 @@ alert(`${title} ${width} ${height}`); // Меню 100 200
|
|||
//+ run
|
||||
'use strict';
|
||||
|
||||
let menuOptions = {
|
||||
let options = {
|
||||
title: "Меню"
|
||||
};
|
||||
|
||||
*!*
|
||||
let {width:w=100, height:h=200, title} = menuOptions;
|
||||
let {width:w=100, height:h=200, title} = options;
|
||||
*/!*
|
||||
|
||||
alert(`${title} ${w} ${h}`); // Меню 100 200
|
||||
```
|
||||
|
||||
А что, если в объекте больше значений, чем переменных? Можно ли куда-то присвоить "остаток"?
|
||||
А что, если в объекте больше значений, чем переменных? Можно ли куда-то присвоить "остаток", аналогично массивам?
|
||||
|
||||
Такой возможности в текущем стандарте нет. Она планируется в будущем стандарте, и выглядеть она будет аналогично массивам:
|
||||
Такой возможности в текущем стандарте нет. Она планируется в будущем стандарте, и выглядеть она будет примерно так:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
'use strict';
|
||||
|
||||
let menuOptions = {
|
||||
let options = {
|
||||
title: "Меню",
|
||||
width: 100,
|
||||
height: 200
|
||||
};
|
||||
|
||||
*!*
|
||||
let {title, ...size} = menuOptions;
|
||||
let {title, ...size} = options;
|
||||
*/!*
|
||||
|
||||
// title = "Меню"
|
||||
|
@ -195,22 +219,25 @@ let {title, ...size} = menuOptions;
|
|||
|
||||
[smart header="Деструктуризация без объявления"]
|
||||
|
||||
В примерах выше переменные объявлялись прямо перед присваиванием. Конечно, можно использовать и уже существующие переменные.
|
||||
В примерах выше переменные объявлялись прямо перед присваиванием: `let {…} = {…}`. Конечно, можно и без `let`, использовать уже существующие переменные.
|
||||
|
||||
Однако, для объектов есть небольшой "подвох". В JavaScript, если в основном потоке кода (не внутри другого выражения) встречается `{...}`, то это воспринимается как блок.
|
||||
Однако, здесь есть небольшой "подвох". В JavaScript, если в основном потоке кода (не внутри другого выражения) встречается `{...}`, то это воспринимается как блок.
|
||||
|
||||
Например, можно использовать для ограничения видимости переменных:
|
||||
Например, можно использовать такой блок для ограничения видимости переменных:
|
||||
```js
|
||||
//+ run
|
||||
'use strict';
|
||||
{
|
||||
// вспомогательные переменные, локальные для блока
|
||||
let a = 5;
|
||||
// поработали с ними
|
||||
alert(a); // 5
|
||||
// больше эти переменные не нужны
|
||||
}
|
||||
alert(a); // ошибка нет такой переменной
|
||||
```
|
||||
|
||||
...Но в данном случае это создаст проблему при деструктуризации:
|
||||
Конечно, это бывает удобно, но в данном случае это создаст проблему при деструктуризации:
|
||||
|
||||
```js
|
||||
let a, b;
|
||||
|
@ -227,15 +254,17 @@ let a, b;
|
|||
|
||||
## Вложенные деструктуризации
|
||||
|
||||
Если объект или массив содержат другие объекты или массивы, и их тоже хочется разбить на переменные -- не проблема.
|
||||
|
||||
Деструктуризации можно как угодно сочетать и вкладывать друг в друга.
|
||||
|
||||
Пример с подобъектом и подмассивом:
|
||||
В коде ниже `options` содержит подобъект и подмассив. В деструктуризации ниже сохраняется та же структура:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
'use strict';
|
||||
|
||||
let menuOptions = {
|
||||
let options = {
|
||||
size: {
|
||||
width: 100,
|
||||
height: 200
|
||||
|
@ -243,16 +272,14 @@ let menuOptions = {
|
|||
items: ["Пончик", "Пирожное"]
|
||||
}
|
||||
|
||||
let {
|
||||
title="Меню",
|
||||
size: {width, height},
|
||||
items: [item1, item2]
|
||||
} = menuOptions;
|
||||
let { title="Меню", size: {width, height}, items: [item1, item2] } = options;
|
||||
|
||||
// Меню 100 200 Пончик Пирожное
|
||||
alert(`${title} ${width} ${height} ${item1} ${item2}`);
|
||||
```
|
||||
|
||||
Как видно, весь объект `options` корректно разбит на переменные.
|
||||
|
||||
|
||||
## Итого
|
||||
|
||||
|
@ -261,14 +288,19 @@ alert(`${title} ${width} ${height} ${item1} ${item2}`);
|
|||
<li>Синтаксис:
|
||||
```js
|
||||
let {prop : varName = default, ...} = object
|
||||
let [var1=default, var2, ...rest] = array
|
||||
```
|
||||
|
||||
Здесь двоеточие `:` задаёт отображение свойства в переменную, а `=` задаёт выражение, которое будет использовано, если значение отсутствует (не указано или `undefined`).
|
||||
Здесь двоеточие `:` задаёт отображение свойства `prop` в переменную `varName`, а равенство `=default` задаёт выражение, которое будет использовано, если значение отсутствует (не указано или `undefined`).
|
||||
|
||||
Для массивов имеет значение порядок, поэтому нельзя использовать `:`, но значение по умолчанию -- можно:
|
||||
|
||||
```js
|
||||
let [var1 = default, var2, ...rest] = array
|
||||
```
|
||||
|
||||
Объявление переменной в начале конструкции не обязательно. Можно использовать и существующие переменные. Однако при деструктуризации объекта может потребоваться обернуть выражение в скобки.
|
||||
</li>
|
||||
<li>Вложенные объекты и массивы тоже работают, деструктуризации можно вкладывать друг в друга, сохраняя ту же структуру, что и исходный объект/массив.</li>
|
||||
<li>Вложенные объекты и массивы тоже работают, при деструктуризации нужно лишь сохранить ту же структуру, что и исходный объект/массив.</li>
|
||||
</ul>
|
||||
|
||||
Как мы увидим далее, деструктуризации особенно пригодятся удобны при чтении объектных параметров функций.
|
||||
|
|
|
@ -84,7 +84,7 @@ function f(arg1, ...rest, arg2) { // arg2 после ...rest ?!
|
|||
[/warn]
|
||||
|
||||
|
||||
Выше мы увидели использование `...` для чтения параметров внутри функции. Но этот же оператор можно использовать и для передачи массива параметров как списка, например:
|
||||
Выше мы увидели использование `...` для чтения параметров в объявлении функции. Но этот же оператор можно использовать и при вызове функции, для передачи массива параметров как списка, например:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
@ -92,19 +92,22 @@ function f(arg1, ...rest, arg2) { // arg2 после ...rest ?!
|
|||
|
||||
let numbers = [2, 3, 15];
|
||||
|
||||
// Передаст массив как список аргументов: Math.max(2, 3, 15)
|
||||
// Оператор ... в вызове передаст массив как список аргументов
|
||||
// Этот вызов аналогичен Math.max(2, 3, 15)
|
||||
let max = Math.max(*!*...numbers*/!*);
|
||||
|
||||
alert( max ); // 15
|
||||
```
|
||||
|
||||
Эти два вызова делают одно и то же:
|
||||
Формально говоря, эти два вызова делают одно и то же:
|
||||
|
||||
```js
|
||||
Math.max(...numbers);
|
||||
Math.max.apply(Math, numbers);
|
||||
```
|
||||
|
||||
Похоже, что первый -- короче и красивее.
|
||||
|
||||
## Деструктуризация в параметрах
|
||||
|
||||
Если функция получает объект, то она может его тут же разбить в переменные:
|
||||
|
@ -113,7 +116,7 @@ Math.max.apply(Math, numbers);
|
|||
//+ run
|
||||
'use strict';
|
||||
|
||||
let menuOptions = {
|
||||
let options = {
|
||||
title: "Меню",
|
||||
width: 100,
|
||||
height: 200
|
||||
|
@ -125,7 +128,7 @@ function showMenu({title, width, height}) {
|
|||
alert(`${title} ${width} ${height}`); // Меню 100 200
|
||||
}
|
||||
|
||||
showMenu(menuOptions);
|
||||
showMenu(options);
|
||||
```
|
||||
|
||||
Можно использовать и более сложную деструктуризацию, с соответствиями и значениями по умолчанию:
|
||||
|
@ -134,21 +137,36 @@ showMenu(menuOptions);
|
|||
//+ run
|
||||
'use strict';
|
||||
|
||||
let menuOptions = {
|
||||
let options = {
|
||||
title: "Меню"
|
||||
};
|
||||
|
||||
*!*
|
||||
function showMenu({title="Заголовок", width:w=100, height:h=200} = {}) {
|
||||
function showMenu({title="Заголовок", width:w=100, height:h=200}) {
|
||||
*/!*
|
||||
alert(`${title} ${w} ${h}`);
|
||||
}
|
||||
|
||||
showMenu(menuOptions); // Меню 100 200
|
||||
// объект options будет разбит на переменные
|
||||
showMenu(options); // Меню 100 200
|
||||
```
|
||||
|
||||
Заметим, что в примере выше какой-то аргумент у `showMenu()` обязательно должен быть, чтобы разбить его на переменные.
|
||||
|
||||
Если хочется, чтобы функция могла быть вызвана вообще без аргументов -- нужно добавить ей параметр по умолчанию -- уже не внутрь деструктуризации, а в самом списке аргументов:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
'use strict';
|
||||
|
||||
function showMenu({title="Заголовок", width:w=100, height:h=200} *!*= {}*/!*) {
|
||||
alert(`${title} ${w} ${h}`);
|
||||
}
|
||||
|
||||
showMenu(); // Заголовок 100 200
|
||||
```
|
||||
|
||||
|
||||
## Имя "name"
|
||||
|
||||
В свойстве `name` у функции находится её имя.
|
||||
|
@ -166,19 +184,23 @@ let g = function g() {}; // g.name == "g"
|
|||
alert(`${f.name} ${g.name}`) // f g
|
||||
```
|
||||
|
||||
В примере выше показаны Function Declaration и Named Function Expression.
|
||||
В примере выше показаны Function Declaration и Named Function Expression. В синтаксисе выше довольно очевидно, что у этих функций есть имя `name`. В конце концов, оно указано в объявлении.
|
||||
|
||||
Но современный JavaScript идёт дальше, он старается даже анонимным функциям дать разумные имена.
|
||||
|
||||
Например, при создании анонимной функции с одновременной записью в переменную или свойство -- её имя равно названию переменной (или свойства):
|
||||
Например, при создании анонимной функции с одновременной записью в переменную или свойство -- её имя равно названию переменной (или свойства).
|
||||
|
||||
Например:
|
||||
|
||||
```js
|
||||
'use strict';
|
||||
|
||||
let g = function() {}; // g.name == "g"
|
||||
// свойство g.name = "g"
|
||||
let g = function() {};
|
||||
|
||||
let user = {
|
||||
sayHi: function() { }; // user.sayHi.name == "sayHi"
|
||||
// свойство user.sayHi.name == "sayHi"
|
||||
sayHi: function() { };
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -204,7 +226,7 @@ if (true) {
|
|||
sayHi(); // ошибка, функции не существует
|
||||
```
|
||||
|
||||
То есть, иными словами, такое объявление -- ведёт себя так же как `let sayHi = function ...`, сделанное в начале блока.
|
||||
То есть, иными словами, такое объявление -- ведёт себя в точности как если бы `let sayHi = function() {…}` было сделано в начале блока.
|
||||
|
||||
## Функции через =>
|
||||
|
||||
|
@ -222,8 +244,6 @@ let inc = x => x+1;
|
|||
alert( inc(1) ); // 2
|
||||
```
|
||||
|
||||
То есть, слева от `=>` находится аргумент, а справа -- выражение, которое нужно вернуть.
|
||||
|
||||
Эти две записи -- примерно аналогичны:
|
||||
|
||||
```js
|
||||
|
@ -232,7 +252,9 @@ let inc = x => x+1;
|
|||
let inc = function(x) { return x + 1; };
|
||||
```
|
||||
|
||||
Если аргументов несколько, то они оборачиваются в скобки, например:
|
||||
Как видно, `"x => x+1"` -- это уже готовая функция. Слева от `=>` находится аргумент, а справа -- выражение, которое нужно вернуть.
|
||||
|
||||
Если аргументов несколько, то нужно обернуть их в скобки, вот так:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
@ -242,16 +264,20 @@ let inc = function(x) { return x + 1; };
|
|||
let sum = (a,b) => a + b;
|
||||
*/!*
|
||||
|
||||
// аналог с function
|
||||
// let inc = function(a, b) { return a + b; };
|
||||
|
||||
alert( sum(1, 2) ); // 3
|
||||
```
|
||||
|
||||
...А если совсем нет аргументов, но функцию хочется задать, то используются пустые скобки:
|
||||
Если нужно задать функцию без аргументов, то также используются скобки, в этом случае -- пустые:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
'use strict';
|
||||
|
||||
*!*
|
||||
// вызов getTime() будет возвращать текущее время
|
||||
let getTime = () => `${new Date().getHours()} : ${new Date().getMinutes()}`;
|
||||
*/!*
|
||||
|
||||
|
@ -277,7 +303,7 @@ let getTime = () => {
|
|||
alert( getTime() ); // текущее время
|
||||
```
|
||||
|
||||
Заметим, что как только тело функции оборачивается в `{…}`, то оно уже автоматически перестаёт быть выражением. Такая функция должна делать явный `return`, как в примере выше, если конечно хочет что-либо возвратить.
|
||||
Заметим, что как только тело функции оборачивается в `{…}`, то её результат уже не возвращается автоматически. Такая функция должна делать явный `return`, как в примере выше, если конечно хочет что-либо возвратить.
|
||||
|
||||
Функции-стрелки очень удобны в качестве коллбеков, например:
|
||||
|
||||
|
@ -294,7 +320,7 @@ let sorted = arr.sort( (a,b) => a - b );
|
|||
alert(sorted); // 3, 5, 8
|
||||
```
|
||||
|
||||
Такая запись -- коротка и понятна.
|
||||
Такая запись -- коротка и понятна. Далее мы познакомимся с дополнительными преимуществами использования функций-стрелок для этой цели.
|
||||
|
||||
## Функции-стрелки не имеют своего this
|
||||
|
||||
|
@ -325,7 +351,7 @@ group.showList();
|
|||
// Наш курс: Даша
|
||||
```
|
||||
|
||||
Здесь в `forEach` была использована функция-стрелка, поэтому `this.title` внутри -- тот же, что и во внешней функции `showList`. То есть, в данном случае -- `group.title`.
|
||||
Здесь в `forEach` была использована функция-стрелка, поэтому `this.title` в коллбэке -- тот же, что и во внешней функции `showList`. То есть, в данном случае -- `group.title`.
|
||||
|
||||
Если бы в `forEach` вместо функции-стрелки была обычная функция, то была бы ошибка:
|
||||
|
||||
|
@ -352,7 +378,7 @@ group.showList();
|
|||
При запуске будет "попытка прочитать свойство `title` у `undefined`", так как `.forEach(f)` при запуске `f` не ставит `this`. То есть, `this` внутри `forEach` будет `undefined`.
|
||||
|
||||
[warn header="Функции стрелки нельзя запускать с `new`"]
|
||||
Отсутствие у функции-стрелки "своего `this`" влечёт за собой естественное ограничение: такие функции нельзя использовать в качестве конструктора, то есть вызывать через `new`.
|
||||
Отсутствие у функции-стрелки "своего `this`" влечёт за собой естественное ограничение: такие функции нельзя использовать в качестве конструктора, то есть нельзя вызывать через `new`.
|
||||
[/warn]
|
||||
|
||||
## Функции-стрелки не имеют своего arguments
|
||||
|
@ -404,8 +430,10 @@ sayHiDeferred("Вася"); // Привет, Вася! через 2 секунд
|
|||
```js
|
||||
function defer(f, ms) {
|
||||
return function() {
|
||||
*!*
|
||||
let args = arguments;
|
||||
let ctx = this;
|
||||
*/!*
|
||||
setTimeout(function() {
|
||||
return f.apply(ctx, args);
|
||||
}, ms);
|
||||
|
@ -413,6 +441,8 @@ function defer(f, ms) {
|
|||
}
|
||||
```
|
||||
|
||||
В этом коде пришлось создавать дополнительные переменные `args` и `ctx` для передачи внешних аргументов и контекста через замыкание.
|
||||
|
||||
|
||||
## Итого
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
let str = `обратные кавычки`;
|
||||
```
|
||||
|
||||
Основные отличия от `"…"` и `'…'`:
|
||||
Основные отличия от двойных `"…"` и одинарных `'…'` кавычек:
|
||||
|
||||
<ul>
|
||||
<li>**В них разрешён перевод строки.**
|
||||
|
@ -38,7 +38,7 @@ let oranges = 3;
|
|||
alert(`${apples} + ${oranges} = ${apples + oranges}`); // 2 + 3 = 5
|
||||
```
|
||||
|
||||
Как видно, можно вставлять как и значение переменной, так и более сложные выражения, вызовы функций и т.п. Это называют "интерполяцией".
|
||||
Как видно, при помощи `${…}` можно вставлять как и значение переменной `${apples}`, так и более сложные выражения, которые могут включать в себя операторы, вызовы функций и т.п. Такую вставку называют "интерполяцией".
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
@ -88,7 +88,9 @@ let str = f`Sum of ${apples} + ${oranges} =\n ${apples + oranges}!`;
|
|||
Это нужно в тех случаях, когда функция шаблонизации хочет произвести обработку полностью самостоятельно (свои спец. символы?). Или же когда обработка спец. символов не нужна -- например, строка содержит "обычный текст", набранный непрограммистом без учёта спец. символов.
|
||||
[/smart]
|
||||
|
||||
Функция может как-то преобразовать строку и вернуть новый результат.
|
||||
Как видно, функция имеет доступ ко всему: к выражениям, к участкам текста и даже, через `strings.raw` -- к оригинально введённому тексту без учёта стандартных спец. символов.
|
||||
|
||||
Функция шаблонизации может как-то преобразовать строку и вернуть новый результат.
|
||||
|
||||
В простейшем случае можно просто "склеить" полученные фрагменты в строку:
|
||||
|
||||
|
@ -116,11 +118,11 @@ let oranges = 5;
|
|||
alert( str`Sum of ${apples} + ${oranges} = ${apples + oranges}!`);
|
||||
```
|
||||
|
||||
Функция `str` в примере выше делает то же самое, что обычные обратные кавычки. Но, конечно, можно пойти намного дальше.
|
||||
Функция `str` в примере выше делает то же самое, что обычные обратные кавычки. Но, конечно, можно пойти намного дальше. Например, генерировать из HTML-строки DOM-узлы (функции шаблонизации не обязательно возвращать именно строку).
|
||||
|
||||
Например, генерировать из HTML-строки DOM-узлы (функции шаблонизации не обязательно возвращать именно строку).
|
||||
Или можно реализовать интернационализацию. В примере ниже функция `i18n` осуществляет перевод строки.
|
||||
|
||||
Или можно реализовать интернационализацию. В примере ниже функция `i18n` подбирает по строке вида `"Hello, ${name}!"` шаблон перевода `"Привет, {0}!"` (где `{0}` -- место для вставки параметра) и возвращает переведённый результат.
|
||||
Она подбирает по строке вида `"Hello, ${name}!"` шаблон перевода `"Привет, {0}!"` (где `{0}` -- место для вставки параметра) и возвращает переведённый результат со вставленным именем `name`:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
|
@ -147,12 +149,16 @@ function i18n(strings, ...values) {
|
|||
}
|
||||
|
||||
// Пример использования
|
||||
*!*
|
||||
let name = "Вася";
|
||||
|
||||
// Перевести строку
|
||||
alert( i18n`Hello, ${name}!` ); // Привет, Вася!
|
||||
*/!*
|
||||
```
|
||||
|
||||
Итоговое использование выглядит довольно красиво, не правда ли?
|
||||
|
||||
Разумеется, эту функцию можно улучшить и расширить. Функция шаблонизации -- это своего рода "стандартный синтаксический сахар" для упрощения форматирования и парсинга строк.
|
||||
|
||||
## Улучшена поддержка юникода
|
||||
|
@ -253,23 +259,24 @@ alert( "\u{20331}" ); // 𠌱, китайский иероглиф с этим
|
|||
|
||||
Например, на основе обычного символа `a` существуют символы: `àáâäãåā`. Самые часто встречающиеся подобные сочетания имеют отдельный юникодный код. Но отнюдь не все.
|
||||
|
||||
Для генерации произвольных сочетаний используются два юникодных символа: основа и значок.
|
||||
Для генерации произвольных сочетаний используются несколько юникодных символов: основа и один или несколько значков.
|
||||
|
||||
Например, если после символа `S` идёт символ "точка сверху" (код `\u0307`), то вместе будет "S с точкой сверху" `Ṡ`.
|
||||
Например, если после символа `S` идёт символ "точка сверху" (код `\u0307`), то показано это будет как "S с точкой сверху" `Ṡ`.
|
||||
|
||||
Если нужен ещё значок над той же буквой (или под ней) -- без проблем. Просто добавляем соответствующий символ.
|
||||
|
||||
К примеру, если добавить символ "точка снизу" (код `\u0323`), то будет "S с двумя точками сверху и снизу" `Ṩ` .
|
||||
|
||||
В JavaScript-строке:
|
||||
Пример этого символа в JavaScript-строке:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
alert("S\u0307\u0323"); // Ṩ
|
||||
```
|
||||
|
||||
Такая возможность добавить произвольной букве нужные значки, с одной стороны, необходима, чтобы не хранить все возможные сочетания (которых громадное число), а с другой стороны -- возникает проблемка -- можно представить одинаковый с точки зрения визуального отображения и интерпретации символ -- разными сочетаниями Unicode-кодов.
|
||||
Такая возможность добавить произвольной букве нужные значки, с одной стороны, необходима, а с другой стороны -- возникает проблемка: можно представить одинаковый с точки зрения визуального отображения и интерпретации символ -- разными сочетаниями Unicode-кодов.
|
||||
|
||||
Вот пример:
|
||||
```js
|
||||
//+ run
|
||||
alert("S\u0307\u0323"); // Ṩ
|
||||
|
@ -278,7 +285,7 @@ alert("S\u0323\u0307"); // Ṩ
|
|||
alert( "S\u0307\u0323" == "S\u0323\u0307" ); // false
|
||||
```
|
||||
|
||||
В первой строке сначала верхняя точка, а потом -- нижняя, во второй -- наоборот. По кодам строки не равны друг другу. Но символ задают один и тот же.
|
||||
В первой строке после основы `S` идёт сначала значок "верхняя точка", а потом -- нижняя, во второй -- наоборот. По кодам строки не равны друг другу. Но символ задают один и тот же.
|
||||
|
||||
|
||||
С целью разрешить эту ситуацию, существует *юникодная нормализация*, при которой строки приводятся к единому, "нормальному", виду.
|
||||
|
@ -300,7 +307,7 @@ alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true
|
|||
|
||||
Это, конечно, не всегда так, просто в данном случае оказалось, что именно такой символ в юникоде уже есть. Если добавить значков, то нормализация уже даст несколько символов.
|
||||
|
||||
Впрочем, для большинства практических задач информации, данной выше, должно быть вполне достаточно, но если хочется более подробно ознакомиться с вариантами и правилами нормализации -- они описаны в приложении к стандарту юникод [Unicode Normalization Forms](http://www.unicode.org/reports/tr15/).
|
||||
Для большинства практических задач информации, данной выше, должно быть вполне достаточно, но если хочется более подробно ознакомиться с вариантами и правилами нормализации -- они описаны в приложении к стандарту юникод [Unicode Normalization Forms](http://www.unicode.org/reports/tr15/).
|
||||
|
||||
## Полезные методы
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue