translating

This commit is contained in:
Ilya Kantor 2016-03-21 10:16:55 +03:00
parent 2b874a73be
commit 928cd2731b
165 changed files with 2046 additions and 2967 deletions

View file

@ -1,11 +0,0 @@
function addClass(obj, cls) {
var classes = obj.className ? obj.className.split(' ') : [];
for (var i = 0; i < classes.length; i++) {
if (classes[i] == cls) return; // класс уже есть
}
classes.push(cls); // добавить
obj.className = classes.join(' '); // и обновить свойство
}

View file

@ -1,33 +0,0 @@
describe("addClass", function() {
it("добавляет класс, которого нет", function() {
var obj = {
className: 'open menu'
};
addClass(obj, 'new');
assert.deepEqual(obj, {
className: 'open menu new'
});
});
it("не добавляет класс, который уже есть", function() {
var obj = {
className: 'open menu'
};
addClass(obj, 'open');
assert.deepEqual(obj, {
className: 'open menu'
});
});
it("не добавляет лишних пробелов, который уже есть", function() {
var obj = {
className: ''
};
addClass(obj, 'open');
assert.deepEqual(obj, {
className: 'open'
});
});
});

View file

@ -1,29 +0,0 @@
Решение заключается в превращении `obj.className` в массив при помощи `split`.
После этого в нем можно проверить наличие класса, и если нет - добавить.
```js run
function addClass(obj, cls) {
var classes = obj.className ? obj.className.split(' ') : [];
for (var i = 0; i < classes.length; i++) {
if (classes[i] == cls) return; // класс уже есть
}
classes.push(cls); // добавить
obj.className = classes.join(' '); // и обновить свойство
}
var obj = {
className: 'open menu'
};
addClass(obj, 'new');
addClass(obj, 'open');
addClass(obj, 'me');
alert(obj.className) // open menu new me
```
P.S. "Альтернативный" подход к проверке наличия класса вызовом `obj.className.indexOf(cls)` был бы неверным. В частности, он найдёт `cls = "menu"` в строке классов `obj.className = "open mymenu"`.
P.P.S. Проверьте, нет ли в вашем решении присвоения `obj.className += " " + cls`. Не добавляет ли оно лишний пробел в случае, если изначально `obj.className = ""`?

View file

@ -1,25 +0,0 @@
importance: 5
---
# Добавить класс в строку
В объекте есть свойство `className`, которое содержит список "классов" - слов, разделенных пробелом:
```js
var obj = {
className: 'open menu'
}
```
Создайте функцию `addClass(obj, cls)`, которая добавляет в список класс `cls`, но только если его там еще нет:
```js
addClass(obj, 'new'); // obj.className='open menu new'
addClass(obj, 'open'); // без изменений (класс уже существует)
addClass(obj, 'me'); // obj.className='open menu new me'
alert( obj.className ); // "open menu new me"
```
P.S. Ваша функция не должна добавлять лишних пробелов.

View file

@ -0,0 +1,8 @@
function camelize(str) {
return str
.split('-') // my-long-word -> ['my', 'long', 'word']
.map(
(word, index) => index == 0 ? word : word[0].toUpperCase() + word.slice(1)
) // ['my', 'long', 'word'] -> ['my', 'Long', 'Word']
.join(''); // ['my', 'Long', 'Word'] -> myLongWord
}

View file

@ -0,0 +1,19 @@
describe("camelize", function() {
it("leaves an empty line as is", function() {
assert.equal(camelize(""), "");
});
it("turns background-color into backgroundColor", function() {
assert.equal(camelize("background-color"), "backgroundColor");
});
it("turns list-style-image into listStyleImage", function() {
assert.equal(camelize("list-style-image"), "listStyleImage");
});
it("turns -webkit-transition into WebkitTransition", function() {
assert.equal(camelize("-webkit-transition"), "WebkitTransition");
});
});

View file

@ -0,0 +1,19 @@
importance: 5
---
# Translate border-left-width to borderLeftWidth
Write the function `camelize(str)` that changes dash-separated words like "my-short-string" into camel-cased "myShortString".
That is: removes all dashes, each word after dash becomes uppercased.
Examples:
```js
camelize("background-color") == 'backgroundColor';
camelize("list-style-image") == 'listStyleImage';
camelize("-webkit-transition") == 'WebkitTransition';
```

View file

@ -1,10 +0,0 @@
function camelize(str) {
var arr = str.split('-');
for (var i = 1; i < arr.length; i++) {
// преобразовать: первый символ с большой буквы
arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].slice(1);
}
return arr.join('');
}

View file

@ -1,22 +0,0 @@
describe("camelize", function() {
it("оставляет пустую строку \"как есть\"", function() {
assert.equal(camelize(""), "");
});
describe("делает заглавным первый символ после дефиса", function() {
it("превращает background-color в backgroundColor", function() {
assert.equal(camelize("background-color"), "backgroundColor");
});
it("превращает list-style-image в listStyleImage", function() {
assert.equal(camelize("list-style-image"), "listStyleImage");
});
it("превращает -webkit-transition в WebkitTransition", function() {
assert.equal(camelize("-webkit-transition"), "WebkitTransition");
});
});
});

View file

@ -1,25 +0,0 @@
# Идея
Задача может быть решена несколькими способами. Один из них -- разбить строку по дефису `str.split('-')`, затем последовательно сконструировать новую.
# Решение
Разобьем строку в массив, а затем преобразуем его элементы и сольём обратно:
```js run
function camelize(str) {
var arr = str.split('-');
for (var i = 1; i < arr.length; i++) {
// преобразовать: первый символ с большой буквы
arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].slice(1);
}
return arr.join('');
}
alert( camelize("background-color") ); // backgroundColor
alert( camelize("list-style-image") ); // listStyleImage
alert( camelize("-webkit-transition") ); // WebkitTransition
```

View file

@ -1,22 +0,0 @@
importance: 3
---
# Перевести текст вида border-left-width в borderLeftWidth
Напишите функцию `camelize(str)`, которая преобразует строки вида "my-short-string" в "myShortString".
То есть, дефисы удаляются, а все слова после них получают заглавную букву.
Например:
```js
camelize("background-color") == 'backgroundColor';
camelize("list-style-image") == 'listStyleImage';
camelize("-webkit-transition") == 'WebkitTransition';
```
Такая функция полезна при работе с CSS.
P.S. Вам пригодятся методы строк `charAt`, `split` и `toUpperCase`.

View file

@ -0,0 +1,5 @@
function filterRange(arr, a, b) {
// added brackets around the expression for better readability
return arr.filter(item => (a <= item && item <= b));
}

View file

@ -0,0 +1,21 @@
describe("filterRange", function() {
it("returns the filtered values", function() {
let arr = [5, 3, 8, 1];
let filtered = filterRange(arr, 1, 4);
assert.deepEqual(filtered, [3, 1]);
});
it("doesn't change the array", function() {
let arr = [5, 3, 8, 1];
let filtered = filterRange(arr, 1, 4);
assert.deepEqual(arr, [5,3,8,1]);
});
});

View file

@ -0,0 +1,22 @@
importance: 4
---
# Filter "in place"
Write a function `filterRange(arr, a, b)` that gets an array `arr`, looks for elements between `a` and `b` in it and returns an array of them.
The function should not modify the array. It should return the new array.
For instance:
```js
let arr = [5, 3, 8, 1];
let filtered = filterRange(arr, 1, 4);
alert( filtered ); // 3,1 (matching values)
alert( arr ); // 5,3,8,1 (not modified)
```

View file

@ -0,0 +1,15 @@
function filterRangeInPlace(arr, a, b) {
for (let i = 0; i < arr.length; i++) {
let val = arr[i];
// remove if outside of the interval
if (val < a || val > b) {
arr.splice(i, 1);
i--;
}
}
}

View file

@ -0,0 +1,16 @@
describe("filterRangeInPlace", function() {
it("returns the filtered values", function() {
let arr = [5, 3, 8, 1];
filterRangeInPlace(arr, 1, 4);
assert.deepEqual(arr, [3, 1]);
});
it("doesn't return anything", function() {
assert.isUndefined(filterRangeInPlace([1,2,3], 1, 4));
});
});

View file

@ -0,0 +1,19 @@
importance: 4
---
# Filter "in place"
Write a function `filterRangeInPlace(arr, a, b)` that gets an array `arr` and removes from it all values except those that are between `a` and `b. The test is: `a ≤ arr[i] ≤ b`.
The function should only modify the array. It should not return anything.
For instance:
```js
let arr = [5, 3, 8, 1];
filterRangeInPlace(arr, 1, 4); // removed the numbers except from 1 to 4
alert( arr ); // [3, 1]
```

View file

@ -1,11 +0,0 @@
function removeClass(obj, cls) {
var classes = obj.className.split(' ');
for (i = 0; i < classes.length; i++) {
if (classes[i] == cls) {
classes.splice(i, 1); // удалить класс
i--;
}
}
obj.className = classes.join(' ');
}

View file

@ -1,43 +0,0 @@
describe("removeClass", function() {
it("ничего не делает, если класса нет", function() {
var obj = {
className: 'open menu'
};
removeClass(obj, 'new');
assert.deepEqual(obj, {
className: 'open menu'
});
});
it("не меняет пустое свойство", function() {
var obj = {
className: ''
};
removeClass(obj, 'new');
assert.deepEqual(obj, {
className: ""
});
});
it("удаляет класс, не оставляя лишних пробелов", function() {
var obj = {
className: 'open menu'
};
removeClass(obj, 'open');
assert.deepEqual(obj, {
className: "menu"
});
});
it("если класс один и он удалён, то результат - пустая строка", function() {
var obj = {
className: "menu"
};
removeClass(obj, 'menu');
assert.deepEqual(obj, {
className: ""
});
});
});

View file

@ -1,32 +0,0 @@
Решение заключается в том, чтобы разбить `className` в массив классов, а затем пройтись по нему циклом. Если класс есть - удаляем его `splice`, заново объединяем массив в строку и присваиваем объекту.
```js run
function removeClass(obj, cls) {
var classes = obj.className.split(' ');
for (i = 0; i < classes.length; i++) {
if (classes[i] == cls) {
classes.splice(i, 1); // удалить класс
*!*
i--; // (*)
*/!*
}
}
obj.className = classes.join(' ');
}
var obj = {
className: 'open menu menu'
}
removeClass(obj, 'blabla');
removeClass(obj, 'menu')
alert(obj.className) // open
```
В примере выше есть тонкий момент. Элементы массива проверяются один за другим. При вызове `splice` удаляется текущий, `i-й` элемент, и те элементы, которые идут дальше, сдвигаются на его место.
Таким образом, **на месте `i` оказывается новый, непроверенный элемент**.
Чтобы это учесть, строчка `(*)` уменьшает `i`, чтобы следующая итерация цикла заново проверила элемент с номером `i`. Без нее функция будет работать с ошибками.

View file

@ -1,32 +0,0 @@
importance: 5
---
# Функция removeClass
У объекта есть свойство `className`, которое хранит список "классов" - слов, разделенных пробелами:
```js
var obj = {
className: 'open menu'
};
```
Напишите функцию `removeClass(obj, cls)`, которая удаляет класс `cls`, если он есть:
```js
removeClass(obj, 'open'); // obj.className='menu'
removeClass(obj, 'blabla'); // без изменений (нет такого класса)
```
P.S. Дополнительное усложнение. Функция должна корректно обрабатывать дублирование класса в строке:
```js
obj = {
className: 'my menu menu'
};
removeClass(obj, 'menu');
alert( obj.className ); // 'my'
```
Лишних пробелов после функции образовываться не должно.

View file

@ -1,10 +0,0 @@
function filterRangeInPlace(arr, a, b) {
for (var i = 0; i < arr.length; i++) {
var val = arr[i];
if (val < a || val > b) {
arr.splice(i--, 1);
}
}
}

View file

@ -1,9 +0,0 @@
describe("filterRangeInPlace", function() {
it("меняет массив, оставляя только значения из диапазона", function() {
var arr = [5, 3, 8, 1];
filterRangeInPlace(arr, 1, 4);
assert.deepEqual(arr, [3, 1]);
});
});

View file

@ -1,20 +0,0 @@
```js run
function filterRangeInPlace(arr, a, b) {
for (var i = 0; i < arr.length; i++) {
var val = arr[i];
if (val < a || val > b) {
arr.splice(i--, 1);
}
}
}
var arr = [5, 3, 8, 1];
filterRangeInPlace(arr, 1, 4);
alert( arr ); // [3, 1]
```

View file

@ -1,19 +0,0 @@
importance: 4
---
# Фильтрация массива "на месте"
Создайте функцию `filterRangeInPlace(arr, a, b)`, которая получает массив с числами `arr` и удаляет из него все числа вне диапазона `a..b`.
То есть, проверка имеет вид `a ≤ arr[i] ≤ b`. Функция должна менять сам массив и ничего не возвращать.
Например:
```js
arr = [5, 3, 8, 1];
filterRangeInPlace(arr, 1, 4); // удалены числа вне диапазона 1..4
alert( arr ); // массив изменился: остались [3, 1]
```

View file

@ -0,0 +1,10 @@
```js run
let arr = [5, 2, 1, -10, 8];
arr.sort((a,b) => b - a);
alert( arr );
```

View file

@ -0,0 +1,14 @@
importance: 4
---
# Sort in the reverse order
```js
let arr = [5, 2, 1, -10, 8];
// ... your code to sort it in the reverse order
alert( arr ); // 8, 5, 2, 1, -10
```

View file

@ -0,0 +1,17 @@
We can use `slice()` to make a copy and run the sort on it:
```js run
function copySorted(arr) {
return arr.slice().sort();
}
let arr = ["HTML", "JavaScript", "CSS"];
*!*
let sorted = copySorted(arr);
*/!*
alert( sorted );
alert( arr );
```

View file

@ -0,0 +1,18 @@
importance: 5
---
# Copy and sort array
We have an array of strings `arr`. We'd like to have a sorted copy of it, but keep `arr` unmodified.
Create a function `copySorted(arr)` that returns such a copy.
```js
let arr = ["HTML", "JavaScript", "CSS"];
let sorted = copySorted(arr);
alert( sorted ); // CSS, HTML, JavaScript
alert( arr ); // HTML, JavaScript, CSS (no changes)
```

View file

@ -1,14 +0,0 @@
```js run
var arr = [5, 2, 1, -10, 8];
function compareReversed(a, b) {
return b - a;
}
arr.sort(compareReversed);
alert( arr );
```

View file

@ -1,16 +0,0 @@
importance: 5
---
# Сортировать в обратном порядке
Как отсортировать массив чисел в обратном порядке?
```js
var arr = [5, 2, 1, -10, 8];
// отсортируйте?
alert( arr ); // 8, 5, 2, 1, -10
```

View file

@ -0,0 +1,17 @@
```js run no-beautify
function getNames(arr) {
return arr.map(item => item.name);
}
let john = { name: "John", age: 25 }
let pete = { name: "Pete", age: 30 }
let mary = { name: "Mary", age: 28 }
let arr = [ john, pete, mary ];
let names = getNames(arr);
alert( names ) // John, Pete, Mary
```

View file

@ -0,0 +1,22 @@
importance: 5
---
# Sort objects
Write the function `getNames(users)` that gets an array of "user" objects with property `name` and returns an array of names.
For instance:
```js no-beautify
let john = { name: "John", age: 25 }
let pete = { name: "Pete", age: 30 }
let mary = { name: "Mary", age: 28 }
let arr = [ john, pete, mary ];
let names = getNames(arr);
alert( names ) // John, Pete, Mary
```

View file

@ -1,13 +0,0 @@
Для копирования массива используем `slice()`, и тут же -- сортировку:
```js run
var arr = ["HTML", "JavaScript", "CSS"];
*!*
var arrSorted = arr.slice().sort();
*/!*
alert( arrSorted );
alert( arr );
```

View file

@ -1,20 +0,0 @@
importance: 5
---
# Скопировать и отсортировать массив
Есть массив строк `arr`. Создайте массив `arrSorted` -- из тех же элементов, но отсортированный.
Исходный массив не должен меняться.
```js
var arr = ["HTML", "JavaScript", "CSS"];
// ... ваш код ...
alert( arrSorted ); // CSS, HTML, JavaScript
alert( arr ); // HTML, JavaScript, CSS (без изменений)
```
Постарайтесь сделать код как можно короче.

View file

@ -1,22 +0,0 @@
# Подсказка
Функция сортировки должна возвращать случайный результат сравнения. Используйте для этого [Math.random](http://javascript.ru/Math.random).
# Решение
Обычно `Math.random()` возвращает результат от `0` до `1`. Вычтем `0.5`, чтобы область значений стала `[-0.5 ... 0.5)`.
```js run
var arr = [1, 2, 3, 4, 5];
*!*
function compareRandom(a, b) {
return Math.random() - 0.5;
}
arr.sort(compareRandom);
*/!*
alert( arr ); // элементы в случайном порядке, например [3,5,1,2,4]
```

View file

@ -1,16 +0,0 @@
importance: 3
---
# Случайный порядок в массиве
Используйте функцию `sort` для того, чтобы "перетрясти" элементы массива в случайном порядке.
```js
var arr = [1, 2, 3, 4, 5];
arr.sort(ваша функция);
alert( arr ); // элементы в случайном порядке, например [3,5,1,2,4]
```

View file

@ -0,0 +1,17 @@
```js run no-beautify
function sortByName(arr) {
arr.sort((a, b) => a.name > b.name);
}
let john = { name: "John", age: 25 };
let pete = { name: "Pete", age: 30 };
let mary = { name: "Mary", age: 28 };
let arr = [ john, pete, mary ];
sortByName(arr);
// now sorted is: [john, mary, pete]
alert(arr[1].name) // Mary
```

View file

@ -0,0 +1,23 @@
importance: 5
---
# Sort objects
Write the function `sortByName(users)` that gets an array of objects with property `name` and sorts it.
For instance:
```js no-beautify
let john = { name: "John", age: 25 }
let pete = { name: "Pete", age: 30 }
let mary = { name: "Mary", age: 28 }
let arr = [ john, pete, mary ];
lsortByName(arr);
// now: [john, mary, pete]
alert(arr[1].name) // Mary
```

View file

@ -0,0 +1,14 @@
```js run
function getAverageAge(users) {
return arr.reduce((prev, user) => prev + user.age, 0) / arr.length;
}
let john = { name: "John", age: 25 }
let pete = { name: "Pete", age: 30 }
let mary = { name: "Mary", age: 29 }
let arr = [ john, pete, mary ];
alert( getAverageAge(arr) ); // 28
```

View file

@ -0,0 +1,22 @@
importance: 4
---
# Get average age
Write the function `getAverageAge(users)` that gets an array of objects with property `age` and gets the average.
The formula for the average is `(age1 + age2 + ... + ageN) / N`.
For instance:
```js no-beautify
let john = { name: "John", age: 25 }
let pete = { name: "Pete", age: 30 }
let mary = { name: "Mary", age: 29 }
let arr = [ john, pete, mary ];
alert( getAverageAge(arr) ); // (25+30+29)/3 = 28
```

View file

@ -1,25 +0,0 @@
Для сортировки объявим и передадим в `sort` анонимную функцию, которая сравнивает объекты по полю `age`:
```js run no-beautify
*!*
// Наша функция сравнения
function compareAge(personA, personB) {
return personA.age - personB.age;
}
*/!*
// проверка
var vasya = { name: "Вася", age: 23 };
var masha = { name: "Маша", age: 18 };
var vovochka = { name: "Вовочка", age: 6 };
var people = [ vasya , masha , vovochka ];
people.sort(compareAge);
// вывести
for(var i = 0; i < people.length; i++) {
alert(people[i].name); // Вовочка Маша Вася
}
```

View file

@ -1,24 +0,0 @@
importance: 5
---
# Сортировка объектов
Напишите код, который отсортирует массив объектов `people` по полю `age`.
Например:
```js no-beautify
var vasya = { name: "Вася", age: 23 };
var masha = { name: "Маша", age: 18 };
var vovochka = { name: "Вовочка", age: 6 };
var people = [ vasya , masha , vovochka ];
... ваш код ...
// теперь people: [vovochka, masha, vasya]
alert(people[0].age) // 6
```
Выведите список имён в массиве после сортировки.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

View file

@ -1,153 +0,0 @@
# Вывод списка в цикле
```js run
var list = {
value: 1,
next: {
value: 2,
next: {
value: 3,
next: {
value: 4,
next: null
}
}
}
};
function printList(list) {
var tmp = list;
while (tmp) {
alert( tmp.value );
tmp = tmp.next;
}
}
printList(list);
```
Обратите внимание, что для прохода по списку используется временная переменная `tmp`, а не `list`. Можно было бы и бегать по списку, используя входной параметр функции:
```js
function printList(list) {
while(*!*list*/!*) {
alert( list.value );
list = list.next;
}
}
```
...Но при этом мы в будущем не сможем расширить функцию и сделать со списком что-то ещё, ведь после окончания цикла начало списка уже нигде не хранится.
Поэтому и используется временная переменная -- чтобы сделать код расширяемым, и, кстати, более понятным, ведь роль `tmp` -- исключительно обход списка, как `i` в цикле `for`.
# Вывод списка с рекурсией
Рекурсивный вариант `printList(list)` следует простой логике: вывести текущее значение `(1)`, а затем пропустить через себя следующее `(2)`:
```js run
var list = {
value: 1,
next: {
value: 2,
next: {
value: 3,
next: {
value: 4,
next: null
}
}
}
};
function printList(list) {
alert( list.value ); // (1)
if (list.next) {
printList(list.next); // (2)
}
}
printList(list);
```
# Обратный вывод с рекурсией
Обратный вывод -- почти то же самое, что прямой, просто сначала мы обрабатываем следующее значение, а потом -- текущее:
```js run
var list = {
value: 1,
next: {
value: 2,
next: {
value: 3,
next: {
value: 4,
next: null
}
}
}
};
function printReverseList(list) {
if (list.next) {
printReverseList(list.next);
}
alert( list.value );
}
printReverseList(list);
```
# Обратный вывод без рекурсии
```js run
var list = {
value: 1,
next: {
value: 2,
next: {
value: 3,
next: {
value: 4,
next: null
}
}
}
};
function printReverseList(list) {
var arr = [];
var tmp = list;
while (tmp) {
arr.push(tmp.value);
tmp = tmp.next;
}
for (var i = arr.length - 1; i >= 0; i--) {
alert( arr[i] );
}
}
printReverseList(list);
```
**Обратный вывод без рекурсии быстрее.**
По сути, рекурсивный вариант и нерекурсивный работают одинаково: они проходят список и запоминают его элементы, а потом выводят в обратном порядке.
В случае с массивом это очевидно, а для рекурсии запоминание происходит в стеке (внутренней специальной структуре данных): когда вызывается вложенная функция, то интерпретатор сохраняет в стек текущие параметры. Вложенные вызовы заполняют стек, а потом он выводится в обратном порядке.
При этом, при рекурсии в стеке сохраняется не только элемент списка, а другая вспомогательная информация, необходимая для возвращения из вложенного вызова. Поэтому тратится больше памяти. Все эти расходы отсутствуют во варианте без рекурсии, так как в массиве хранится именно то, что нужно.
Преимущество рекурсии, с другой стороны -- более короткий и, зачастую, более простой код.

View file

@ -1,49 +0,0 @@
importance: 5
---
# Вывести односвязный список
[Односвязный список](http://ru.wikipedia.org/wiki/Связный_список) -- это структура данных, которая состоит из *элементов*, каждый из которых хранит ссылку на следующий. Последний элемент может не иметь ссылки, либо она равна `null`.
Например, объект ниже задаёт односвязный список, в `next` хранится ссылка на следующий элемент:
```js
var list = {
value: 1,
next: {
value: 2,
next: {
value: 3,
next: {
value: 4,
next: null
}
}
}
};
```
Графическое представление этого списка:
![](linked-list.png)
Альтернативный способ создания:
```js no-beautify
var list = { value: 1 };
list.next = { value: 2 };
list.next.next = { value: 3 };
list.next.next.next = { value: 4 };
```
Такая структура данных интересна тем, что можно очень быстро разбить список на части, объединить списки, удалить или добавить элемент в любое место, включая начало. При использовании массива такие действия требуют обширных перенумерований.
Задачи:
1. Напишите функцию `printList(list)`, которая выводит элементы списка по очереди, при помощи цикла.
2. Напишите функцию `printList(list)` при помощи рекурсии.
3. Напишите функцию `printReverseList(list)`, которая выводит элементы списка в обратном порядке, при помощи рекурсии.
Для списка выше она должна выводить `4`,`3`,`2`,`1`
4. Сделайте вариант `printReverseList(list)`, использующий не рекурсию, а цикл.
Как лучше -- с рекурсией или без?

View file

@ -1,234 +1,196 @@
# Массивы: методы
# Array methods
В этой главе мы рассмотрим встроенные методы массивов JavaScript.
Arrays provide a lot of methods. In this chapter we'll study them more in-depth.
[cut]
## Метод split
## split and join
Ситуация из реальной жизни. Мы пишем сервис отсылки сообщений и посетитель вводит имена тех, кому его отправить: `Маша, Петя, Марина, Василий...`. Но нам-то гораздо удобнее работать с массивом имен, чем с одной строкой.
The situation from the real life. We are writing a messaging app, and the person enters the comma-delimited list of receivers: `John, Pete, Mary`. But for us an array of nameswould be much more comfortable than a single string.
К счастью, есть метод `split(s)`, который позволяет превратить строку в массив, разбив ее по разделителю `s`. В примере ниже таким разделителем является строка из запятой и пробела.
The [str.split(s)](mdn:js/String/split) method turns the string into array splitting it by the given delimiter `s`.
In the example below, we split by a comma and a space:
```js run
var names = 'Маша, Петя, Марина, Василий';
let names = 'Bilbo, Gandalf, Nazgul';
var arr = names.split(', ');
let arr = names.split(', ');
for (var i = 0; i < arr.length; i++) {
alert( 'Вам сообщение ' + arr[i] );
for (let name of arr) {
alert( `A message to ${name}.` ); // A message to Bilbo (and other names)
}
```
````smart header="Второй аргумент `split`"
У метода `split` есть необязательный второй аргумент -- ограничение на количество элементов в массиве. Если их больше, чем указано -- остаток массива будет отброшен:
The `split` method has an optional second numeric argument -- a limit on the array length. If it is provided, then the extra elements are ignored. In practice it is rarely used though:
```js run
alert( "a,b,c,d".split(',', *!*2*/!*) ); // a,b
let arr = 'Bilbo, Gandalf, Nazgul, Saruman'.split(', ', 2);
alert(arr); // Bilbo, Gandalf
```
````smart header="Split into letters"
The call to `split(s)` with an empty `s` would split the string into an array of letters:
```js run
let str = "test";
alert( str.split('') ); // t,e,s,t
```
````
````smart header="Разбивка по буквам"
Вызов `split` с пустой строкой разобьёт по буквам:
The call [arr.join(str)](mdn:js/Array/join) does the reverse to `split`. It creates a string of `arr` items glued by `str` beween them.
For instance:
```js run
var str = "тест";
let arr = ['Bilbo', 'Gandalf', 'Nazgul'];
alert( str.split('') ); // т,е,с
```
````
let str = arr.join(';');
## Метод join
Вызов `arr.join(str)` делает в точности противоположное `split`. Он берет массив и склеивает его в строку, используя `str` как разделитель.
Например:
```js run
var arr = ['Маша', 'Петя', 'Марина', 'Василий'];
var str = arr.join(';');
alert( str ); // Маша;Петя;Марина;Василий
alert( str ); // Bilbo;Gandalf;Nazgul
```
````smart header="new Array + join = Повторение строки"
Код для повторения строки `3` раза:
## splice
How to delete an element from the array?
The arrays are objects, so we can use a generic `delete` call:
```js run
alert( new Array(4).join("ля") ); // ляляля
```
var arr = ["I", "go", "home"];
Как видно, `new Array(4)` делает массив без элементов длины 4, который `join` объединяет в строку, вставляя *между его элементами* строку `"ля"`.
delete arr[1]; // remove "go"
В результате, так как элементы пусты, получается повторение строки. Такой вот небольшой трюк.
````
## Удаление из массива
Так как массивы являются объектами, то для удаления ключа можно воспользоваться обычным `delete`:
```js run
var arr = ["Я", "иду", "домой"];
delete arr[1]; // значение с индексом 1 удалено
// теперь arr = ["Я", undefined, "домой"];
// now arr = ["I", , "home"];
alert( arr[1] ); // undefined
```
Да, элемент удален из массива, но не так, как нам этого хочется. Образовалась "дырка".
The element was removed, but the array still has `arr.length == 3`.
Это потому, что оператор `delete` удаляет пару "ключ-значение". Это -- все, что он делает. Обычно же при удалении из массива мы хотим, чтобы оставшиеся элементы сдвинулись и заполнили образовавшийся промежуток.
That's natural, because `delete obj.key` removes a value by the `key`. It's all it does. Fine for objects. But for arrays we usually want the rest of elements to shift and occupy the freed place. We expect to have a shorter array now.
Поэтому для удаления используются специальные методы: из начала -- `shift`, с конца -- `pop`, а из середины -- `splice`, с которым мы сейчас познакомимся.
So, special methods should be used.
## Метод splice
The [arr.splice(str)](mdn:js/Array/splice) method is a swiss army knife for arrays. It can do everything: add, remove and insert elements.
Метод `splice` -- это универсальный раскладной нож для работы с массивами. Умеет все: удалять элементы, вставлять элементы, заменять элементы -- по очереди и одновременно.
The syntax is:
Его синтаксис:
```
arr.splice(index[, deleteCount, elem1, ..., elemN])
```
`arr.splice(index[, deleteCount, elem1, ..., elemN])`
: Удалить `deleteCount` элементов, начиная с номера `index`, а затем вставить `elem1, ..., elemN` на их место. Возвращает массив из удалённых элементов.
It removes `deleteCount` elements, starting from the index `index`, and then inserts `elem1, ..., elemN` at their place. Returns the array of removed elements.
Этот метод проще всего понять, рассмотрев примеры.
This method is easy to grasp by examples.
Начнём с удаления:
Let's start with the deletion:
```js run
var arr = ["Я", "изучаю", "JavaScript"];
let arr = ["I", "study", "JavaScript"];
*!*
arr.splice(1, 1); // начиная с позиции 1, удалить 1 элемент
arr.splice(1, 1); // from index 1 remove 1 element
*/!*
alert( arr ); // осталось ["Я", "JavaScript"]
alert( arr ); // ["I", "JavaScript"]
```
В следующем примере мы удалим 3 элемента и вставим другие на их место:
In the next example we remove 3 elements and replace them by the other two:
```js run
var arr = [*!*"Я", "сейчас", "изучаю",*/!* "JavaScript"];
let arr = [*!*"I", "study", "JavaScript",*/!* "right", "now"];
// удалить 3 первых элемента и добавить другие вместо них
arr.splice(0, 3, "Мы", "изучаем")
// remove 3 first elements and replace them by another
arr.splice(0, 3, "Let's", "dance")
alert( arr ) // теперь [*!*"Мы", "изучаем"*/!*, "JavaScript"]
alert( arr ) // now [*!*"Let's", "dance"*/!*, "right", "now"]
```
Здесь видно, что `splice` возвращает массив из удаленных элементов:
Here we can see that `splice` returns the array of removed elements:
```js run
var arr = [*!*"Я", "сейчас",*/!* "изучаю", "JavaScript"];
let arr = [*!*"I", "study",*/!* "JavaScript", "right", "now"];
// удалить 2 первых элемента
var removed = arr.splice(0, 2);
// remove 2 first elements
let removed = arr.splice(0, 2);
alert( removed ); // "Я", "сейчас" <-- array of removed elements
alert( removed ); // "I", "study" <-- array of removed elements
```
Метод `splice` также может вставлять элементы без удаления, для этого достаточно установить `deleteCount` в `0`:
The `splice` method is also able to only insert the elements, without any removals. For that we need to set `deleteCount` to `0`:
```js run
var arr = ["Я", "изучаю", "JavaScript"];
let arr = ["I", "study", "JavaScript"];
// с позиции 2
// удалить 0
// вставить "сложный", "язык"
arr.splice(2, 0, "сложный", "язык");
// from index 2
// delete 0
// then insert "complex" and "language"
arr.splice(2, 0, "complex", "language");
alert( arr ); // "Я", "изучаю", "сложный", "язык", "JavaScript"
alert( arr ); // "I", "study", "complex", "language", "JavaScript"
```
Допускается использование отрицательного номера позиции, которая в этом случае отсчитывается с конца:
````smart header="Negative indexes allowed"
Here and in other array methods, negative indexes are allowed. The specify the position from the end of the array, like here:
```js run
var arr = [1, 2, 5]
let arr = [1, 2, 5]
// начиная с позиции индексом -1 (предпоследний элемент)
// удалить 0 элементов,
// затем вставить числа 3 и 4
// from index -1 (one step from the end)
// delete 0 elements,
// then insert 3 and 4
arr.splice(-1, 0, 3, 4);
alert( arr ); // результат: 1,2,3,4,5
alert( arr ); // 1,2,3,4,5
```
````
## Метод slice
## sort(fn)
Метод `slice(begin, end)` копирует участок массива от `begin` до `end`, не включая `end`. Исходный массив при этом не меняется.
The method [arr.sort()](mdn:js/Array/sort) sorts the array *at place*.
Например:
For instance:
```js run
var arr = ["Почему", "надо", "учить", "JavaScript"];
var arr2 = arr.slice(1, 3); // элементы 1, 2 (не включая 3)
alert( arr2 ); // надо, учить
```
Аргументы ведут себя так же, как и в строковом `slice`:
- Если не указать `end` -- копирование будет до конца массива:
```js run
var arr = ["Почему", "надо", "учить", "JavaScript"];
alert( arr.slice(1) ); // взять все элементы, начиная с номера 1
```
- Можно использовать отрицательные индексы, они отсчитываются с конца:
```js
var arr2 = arr.slice(-2); // копировать от 2го элемента с конца и дальше
```
- Если вообще не указать аргументов -- скопируется весь массив:
```js
var fullCopy = arr.slice();
```
```smart header="Совсем как в строках"
Синтаксис метода `slice` одинаков для строк и для массивов. Тем проще его запомнить.
```
## Сортировка, метод sort(fn)
Метод `sort()` сортирует массив *на месте*. Например:
```js run
var arr = [ 1, 2, 15 ];
let arr = [ 1, 2, 15 ];
// the method reorders the content of arr (and returns it)
arr.sort();
alert( arr ); // *!*1, 15, 2*/!*
```
Не заметили ничего странного в этом примере?
Did you notice anything strange in the outcome?
Порядок стал `1, 15, 2`, это точно не сортировка чисел. Почему?
The order became `1, 15, 2`. Incorrect. But why?
**Это произошло потому, что по умолчанию `sort` сортирует, преобразуя элементы к строке.**
**The items are sorted as strings by default.**
Поэтому и порядок у них строковый, ведь `"2" > "15"`.
Literally, all elements are converted to strings and then compared. So, the lexicographic ordering is applied and indeed `"2" > "15"`.
### Свой порядок сортировки
To use our own sorting order, we need to supply a function of two arguments as the argument of `arr.sort()`.
Для указания своего порядка сортировки в метод `arr.sort(fn)` нужно передать функцию `fn` от двух элементов, которая умеет сравнивать их.
The function should work like this:
```js
function compare(a, b) {
if (a > b) return 1;
if (a == b) return 0;
if (a < b) return -1;
}
```
Внутренний алгоритм функции сортировки умеет сортировать любые массивы -- апельсинов, яблок, пользователей, и тех и других и третьих -- чего угодно. Но для этого ему нужно знать, как их сравнивать. Эту роль и выполняет `fn`.
Если эту функцию не указать, то элементы сортируются как строки.
Например, укажем эту функцию явно, отсортируем элементы массива как числа:
For instance:
```js run
function compareNumeric(a, b) {
if (a > b) return 1;
if (a == b) return 0;
if (a < b) return -1;
}
var arr = [ 1, 2, 15 ];
let arr = [ 1, 2, 15 ];
*!*
arr.sort(compareNumeric);
@ -237,163 +199,292 @@ arr.sort(compareNumeric);
alert(arr); // *!*1, 2, 15*/!*
```
Обратите внимание, мы передаём в `sort()` именно саму функцию `compareNumeric`, без вызова через скобки. Был бы ошибкой следующий код:
Now it works as intended.
```js
arr.sort( compareNumeric*!*()*/!* ); // не сработает
```
Let's step aside and thing what's happening. The `arr` can be array of anything, right? It may contain numbers or strings or html elements or whatever. We have a set of something. To sort it, we need an *ordering function* that knows how to compare the elements. The default is a string order.
Как видно из примера выше, функция, передаваемая `sort`, должна иметь два аргумента.
The `arr.sort(fn)` method has a built-in implementation of a sorting algorithm. We don't need to care which one (an optimized [quicksort](https://en.wikipedia.org/wiki/Quicksort) most of time). It will walk the array, compare its elements using the provided function and reorder them.
Алгоритм сортировки, встроенный в JavaScript, будет передавать ей для сравнения элементы массива. Она должна возвращать:
So, `arr.sort(fn)` is like a black box for us.
- Положительное значение, если `a > b`,
- Отрицательное значение, если `a < b`,
- Если равны -- можно `0`, но вообще -- не важно, что возвращать, их взаимный порядок не имеет значения.
1. We've got an array of some items to sort.
2. We call `sort(fn)` providing the function that knows how to compare.
3. It sorts.
````smart header="Алгоритм сортировки"
В методе `sort`, внутри самого интерпретатора JavaScript, реализован универсальный алгоритм сортировки. Как правило, это ["\"быстрая сортировка\""](http://algolist.manual.ru/sort/quick_sort.php), дополнительно оптимизированная для небольших массивов.
Он решает, какие пары элементов и когда сравнивать, чтобы отсортировать побыстрее. Мы даём ему функцию -- способ сравнения, дальше он вызывает её сам.
Кстати, те значения, с которыми `sort` вызывает функцию сравнения, можно увидеть, если вставить в неё `alert`:
By the way, if we ever want to know which elements are compared -- nothing prevents from alerting them:
```js run
[1, -2, 15, 2, 0, 8].sort(function(a, b) {
alert( a + " <> " + b );
});
```
The algorithm may compare an element with multiple other elements. But it tries to make as few comparisons as possible.
````smart header="A comparison function may return any number"
Actually, a comparison function is only required to return a positive number to say "greater" and a negative number to say "less".
That allows to write shorter functions:
```js run
let arr = [ 1, 2, 15 ];
arr.sort(function(a, b) { return a - b; });
alert(arr); // *!*1, 2, 15*/!*
```
````
````smart header="Сравнение `compareNumeric` в одну строку"
Функцию `compareNumeric` для сравнения элементов-чисел можно упростить до одной строчки.
````smart header="Arrow functions for the best"
Remember [arrow functions](info:function-expression#arrow-functions)? We can use them here for neater sorting:
```js
function compareNumeric(a, b) {
return a - b;
}
```js
arr.sort( (a, b) => a - b );
```
Эта функция вполне подходит для `sort`, так как возвращает положительное число, если `a > b`, отрицательное, если наоборот, и `0`, если числа равны.
This would work exactly the same as a longer function expression above.
````
## reverse
## indexOf/lastIndexOf and includes
Метод [arr.reverse()](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/reverse) меняет порядок элементов в массиве на обратный.
The methods [arr.indexOf](mdn:js/Array/indexOf), [arr.lastIndexOf](mdn:js/Array/lastIndexOf) and [arr.includes](mdn:js/Array/includes) are the same as their string counterparts.
For instance:
```js run
var arr = [1, 2, 3];
arr.reverse();
alert( arr ); // 3,2,1
```
## concat
Метод [arr.concat(value1, value2, ... valueN)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/concat) создаёт новый массив, в который копируются элементы из `arr`, а также `value1, value2, ... valueN`.
Например:
```js run
var arr = [1, 2];
*!*
var newArr = arr.concat(3, 4);
*/!*
alert( newArr ); // 1,2,3,4
```
У `concat` есть одна забавная особенность.
Если аргумент `concat` -- массив, то `concat` добавляет элементы из него.
Например:
```js run
var arr = [1, 2];
*!*
var newArr = arr.concat([3, 4], 5); // то же самое, что arr.concat(3,4,5)
*/!*
alert( newArr ); // 1,2,3,4,5
```
## indexOf/lastIndexOf
Эти методы не поддерживаются в IE8-. Для их поддержки подключите библиотеку [ES5-shim](https://github.com/kriskowal/es5-shim).
Метод ["arr.indexOf(searchElement[, fromIndex])"](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf) возвращает номер элемента `searchElement` в массиве `arr` или `-1`, если его нет.
Поиск начинается с номера `fromIndex`, если он указан. Если нет -- с начала массива.
**Для поиска используется строгое сравнение `===`.**
Например:
```js run
var arr = [1, 0, false];
let arr = [1, 0, false];
alert( arr.indexOf(0) ); // 1
alert( arr.indexOf(false) ); // 2
alert( arr.indexOf(null) ); // -1
alert( arr.includes(1) ); // true
```
Как вы могли заметить, по синтаксису он полностью аналогичен методу [indexOf для строк](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/indexOf).
Note that the methods use `===` comparison. So, if we look for `false`, it finds exactly `false` and not the zero.
Метод ["arr.lastIndexOf(searchElement[, fromIndex])"](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf) ищет справа-налево: с конца массива или с номера `fromIndex`, если он указан.
```warn header="Методы `indexOf/lastIndexOf` осуществляют поиск перебором"
Если нужно проверить, существует ли значение в массиве -- его нужно перебрать. Только так. Внутренняя реализация `indexOf/lastIndexOf` осуществляет полный перебор, аналогичный циклу `for` по массиву. Чем длиннее массив, тем дольше он будет работать.
```
## find
````smart header="Коллекция уникальных элементов"
Рассмотрим задачу -- есть коллекция строк, и нужно быстро проверять: есть ли в ней какой-то элемент. Массив для этого не подходит из-за медленного `indexOf`. Но подходит объект! Доступ к свойству объекта осуществляется очень быстро, так что можно сделать все элементы ключами объекта и проверять, есть ли уже такой ключ.
Imagine we have an array of objects. How do we find an object with the specific condition?
Например, организуем такую проверку для коллекции строк `"div"`, `"a"` и `"form"`:
Here the [arr.find(fn)](mdn:js/Array/find) method comes in handy.
The syntax is:
```js
var store = {}; // объект для коллекции
var items = ["div", "a", "form"];
for (var i = 0; i < items.length; i++) {
var key = items[i]; // для каждого элемента создаём свойство
store[key] = true; // значение здесь не важно
}
let result = arr.find(function(item, index, array) {
// return true if the item is what we look for
});
```
Теперь для проверки, есть ли ключ `key`, достаточно выполнить `if (store[key])`. Если есть -- можно использовать значение, если нет -- добавить.
The function is called repetitively for each element of the array:
Такое решение работает только со строками, но применимо к любым элементам, для которых можно вычислить строковый "уникальный ключ".
````
- `item` is the element.
- `index` is its index.
- `array` is the array itself.
## Object.keys(obj)
If it returns `true`, the search is stopped, the `item` is returned. If nothing found, `undefined` is returned.
Ранее мы говорили о том, что свойства объекта можно перебрать в цикле `for..in`.
Если мы хотим работать с ними в виде массива, то к нашим услугам -- замечательный метод [Object.keys(obj)](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/keys). Он поддерживается везде, кроме IE8-:
For example, we have an array of users, each with the fields `id` and `name`. Let's find the one with `id == 1`:
```js run
var user = {
name: "Петя",
age: 30
}
let users = [
{id: 1, name: "John"},
{id: 2, name: "Pete"},
{id: 3, name: "Mary"}
];
var keys = Object.keys(user);
let user = users.find(item => item.id == 1);
alert( keys ); // name, age
alert(user.name); // John
```
## Итого
In real life arrays of objects is a common thing, so the `find` method is very useful.
Методы:
Note that in the example we provide to `find` a single-argument function `item => item.id == 1`. It could be longer, like `(item, index, array) => ...`, but the additional parameters are optional. In fact, they are rarely used.
- `push/pop`, `shift/unshift`, `splice` -- для добавления и удаления элементов.
- `join/split` -- для преобразования строки в массив и обратно.
- `sort` -- для сортировки массива. Если не передать функцию сравнения -- сортирует элементы как строки.
- `reverse` -- меняет порядок элементов на обратный.
- `concat` -- объединяет массивы.
- `indexOf/lastIndexOf` -- возвращают позицию элемента в массиве (не поддерживается в IE8-).
Изученных нами методов достаточно в 95% случаях, но существуют и другие. Для знакомства с ними рекомендуется заглянуть в справочник <a href="http://javascript.ru/Array">Array</a> и [Array в Mozilla Developer Network](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array).
## filter
The `find` method looks for a single (first) element that makes the function return `true`.
If there may be multiple, we can use [arr.filter(fn)](mdn:js/Array/filter).
The syntax is roughly the same, but it returns an array of matching elements:
```js run
let users = [
{id: 1, name: "John"},
{id: 2, name: "Pete"},
{id: 3, name: "Mary"}
];
// returns array of the first two users
let someUsers = users.filter(item => item.id < 3);
alert(someUsers.length); // 2
```
## forEach
The [arr.forEach](mdn:js/Array/forEach) method allows to run a function for every element of the array.
The syntax:
```js
arr.forEach(function(item, index, array) {
// ... do something with item
});
```
For instance, this shows each element of the array:
```js run
// for each element call alert
["Bilbo", "Gandalf", "Nazgul"].forEach(alert);
```
And this code is more elaborate about their positions in the target array:
```js run
["Bilbo", "Gandalf", "Nazgul"].forEach((item, index, array) => {
alert(`${item} is at index ${index} in ${array}`);
});
```
The result of the function (if it returns any) is thrown away and ignored.
## map
The [arr.map](mdn:js/Array/map) is used to transform the array.
It calls a function for each element of the array and returns the array of the results.
For instance:
```js run
let lengths = ["Bilbo", "Gandalf", "Nazgul"].map(item => item.length)
alert(lengths); // 5,7,6
```
## reduce/reduceRight
When we need to iterate over an array -- we can use `forEach`.
When we need to iterate and return the data for each element -- we can use `map`.
The methods [arr.reduce](mdn:js/Array/reduce) and [arr.reduceRight](mdn:js/Array/reduceRight) also belong to that breed, but are a little bit more intricate. They are used to calculate a single value based on the array.
The syntax is:
```js
let value = arr.reduce(function(previousValue, item, index, arr) {
// ...
}, initial);
```
The function is applied to the elements. You may notice the familiar arguments, starting from the 2nd:
- `item` -- is the current array item.
- `index` -- is its position.
- `arr` -- is the array.
So far, like `forEach/map`. But there's one more argument:
- `previousValue` -- is the result of the previous function call, `initial` for the first call.
The easiest way to grasp that is by example.
Here we get a sum of array in one line:
```js run
let arr = [1, 2, 3, 4, 5]
let result = arr.reduce((sum, current) => sum + current), 0);
alert( result ); // 15
```
Here we used the most common variant of `reduce` which uses only 2 arguments.
Let's see the details of what's going on.
1. On the first run, `sum` is the initial value (the last argument of `reduce`), equals `0`, and `current` is the first array element, equals `1`. So the result is `1`.
2. On the second run, `sum = 1`, we add the second array element (`2`) to it and return.
3. On the 3rd run, `sum = 3` and we add one more element ot it, and so on...
The calculation flow:
![](reduce.png)
Or in the form of a table, where each row represents is a function call on the next array element:
| |`sum`|`current`|результат|
|---|-----|---------|---------|
|the first call|`0`|`1`|`1`|
|the second call|`1`|`2`|`3`|
|the third call|`3`|`3`|`6`|
|the fourth call|`6`|`4`|`10`|
|the fifth call|`10`|`5`|`15`|
As we can see, the result of the previous call becomes the first argument of the next one.
We also can omit the initial value:
```js run
let arr = [1, 2, 3, 4, 5];
// removed initial value from reduce (no 0)
let result = arr.reduce((sum, current) => sum + current);
alert( result ); // 15
```
The result is the same. That's because if there's no initial, then `reduce` takes the first element of the array as the initial value and starts the iteration from the 2nd element.
The calculation table is the same as above, minus the first row.
But such use requires an extreme care. If the array is empty, then `reduce` call without initial value gives an error. So it's generally advised to specify the initial value.
The method [arr.reduceRight](mdn:js/Array/reduceRight) does the same, but goes from right to left.
## Other methods
We covered the most useful methods. But there are other too, for instance:
- [arr.slice(begin, end)](mdn:js/Array/slice) copies the portion of the array.
It creates a new array and copies elements of `arr` from `begin` to `end` into it. Both arguments are optional: if `end` is omitted, the copying goes till the end, if `begin` is omitted, then from the very beginning. So `arr.slice()` makes a full copy.
- [arr.concat(arr2, arr3...)](mdn:js/Array/concat) joins the arrays.
It creates a new array from elements of `arr`, then appends elements from `arr2` to it, then appends elements from `arr3` and so on.
- [arr.reverse()](mdn:js/Array/reverse) reverses the array.
It creates a new array with elements from `arr` in the reverse order.
- [arr.some(fn)](mdn:js/Array/some)/[arr.every(fn)](mdn:js/Array/every) check the array.
The function `fn` is called on each element of the array similar to `map`. If any/all results are `true`, returns `true`, otherwise `false`.
These and other methods are also listed in the [manual](mdn:js/Array).
## Summary
Most often methods:
- `split/join` -- convert a string to array and back.
- `splice` -- delete and insert elements at the given position.
- `sort` -- sorts the array.
- `indexOf/lastIndexOf`, `includes` -- look for the value.
- `find/filter` -- return first/all values satisfying the given condition.
- `forEach` -- runs a function for each element.
- `map` -- transforms the array through the function.
- `reduce/reduceRight` -- calculates a single value based on array.
- `slice` -- copy the part of the array.
These methods are used in 95% of cases. For the full list, see the [manual](mdn:js/Array).
The methods are easy to remember when you use them. Please refer to the tasks for some practice.

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB