Поиск…


Синтаксис

  • array = [ значение , значение , ... ]
  • array = new Array ( значение , значение , ... )
  • array = Array.of ( значение , значение , ... )
  • array = Array.from ( arrayLike )

замечания

Реферат: Массивы в JavaScript - это довольно просто модифицированные экземпляры Object с расширенным прототипом, способные выполнять множество задач, связанных с списком. Они были добавлены в ECMAScript 1st Edition, а другие прототипы появились в ECMAScript 5.1 Edition.

Предупреждение. Если в new Array() указан числовой параметр n , то он объявит массив с n количеством элементов, а не объявит массив с 1 элементом со значением n !

console.log(new Array(53)); // This array has 53 'undefined' elements!

При этом вы всегда должны использовать [] при объявлении массива:

console.log([53]); // Much better!

Инициализация стандартного массива

Существует много способов создания массивов. Наиболее распространенными являются использование литералов массива или конструктор массива:

var arr = [1, 2, 3, 4];
var arr2 = new Array(1, 2, 3, 4);

Если конструктор Array используется без аргументов, создается пустой массив.

var arr3 = new Array();

результаты:

[]

Обратите внимание: если он используется только с одним аргументом и этот аргумент является number , вместо этого будет создан массив этой длины со всеми undefined значениями:

var arr4 = new Array(4);

результаты:

[undefined, undefined, undefined, undefined]

Это не применяется, если единственный аргумент не является числовым:

var arr5 = new Array("foo");

результаты:

["foo"]
6

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

Array.of(21, "Hello", "World");

результаты:

[21, "Hello", "World"]

В отличие от конструктора Array, создание массива с одним числом, таким как Array.of(23) , создаст новый массив [23] , а не массив длиной 23.

Другим способом создания и инициализации массива будет Array.from

var newArray = Array.from({ length: 5 }, (_, index) => Math.pow(index, 4));

приведет к:

[0, 1, 16, 81, 256]

Распределение / распределение массива

Оператор распространения

6

С ES6 вы можете использовать спреды для разделения отдельных элементов на синтаксис, разделенный запятыми:

let arr = [1, 2, 3, ...[4, 5, 6]];  // [1, 2, 3, 4, 5, 6]

// in ES < 6, the operations above are equivalent to
arr = [1, 2, 3];
arr.push(4, 5, 6);

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

let arr = [1, 2, 3, ...[..."456"].map(x=>parseInt(x))]; // [1, 2, 3, 4, 5, 6]

Или, используя одну строку, это может быть упрощено:

let arr = [..."123456"].map(x=>parseInt(x)); // [1, 2, 3, 4, 5, 6]

Если отображение не выполняется, то:

let arr = [..."123456"]; // ["1", "2", "3", "4", "5", "6"]

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

function myFunction(a, b, c) { }
let args = [0, 1, 2];

myFunction(...args);

// in ES < 6, this would be equivalent to:
myFunction.apply(null, args);

Оператор отдыха

Оператор rest выполняет противоположность оператора спреда путем объединения нескольких элементов в один

[a, b, ...rest] = [1, 2, 3, 4, 5, 6]; // rest is assigned [3, 4, 5, 6]

Соберите аргументы функции:

function myFunction(a, b, ...rest) { console.log(rest); }

myFunction(0, 1, 2, 3, 4, 5, 6); // rest is [2, 3, 4, 5, 6]

Сопоставление значений

Часто бывает необходимо создать новый массив на основе значений существующего массива.

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

5,1
['one', 'two', 'three', 'four'].map(function(value, index, arr) {
  return value.length;
});
// → [3, 3, 5, 4]
6
['one', 'two', 'three', 'four'].map(value => value.length);
// → [3, 3, 5, 4]

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

  • Сам элемент
  • Индекс элемента (0, 1 ...)
  • Весь массив

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

В браузере по умолчанию this всегда window :

['one', 'two'].map(function(value, index, arr) {
  console.log(this); // window (the default value in browsers)
  return value.length;
});

Вы можете изменить его на любой пользовательский объект, например:

['one', 'two'].map(function(value, index, arr) {
  console.log(this); // Object { documentation: "randomObject" }
  return value.length;
}, {
  documentation: 'randomObject'
});

Фильтрация значений

Метод filter() создает массив, заполненный всеми элементами массива, которые проходят тест, предоставляемый как функция.

5,1
[1, 2, 3, 4, 5].filter(function(value, index, arr) {
  return value > 2;
});
6
[1, 2, 3, 4, 5].filter(value => value > 2);

Результаты в новом массиве:

[3, 4, 5]

Фильтровать значения ложности

5,1
var filtered = [ 0, undefined, {}, null, '', true, 5].filter(Boolean);

Поскольку Boolean - это встроенная функция / конструктор javascript, которая принимает [один необязательный параметр], а метод фильтра также принимает функцию и передает ее текущему элементу массива в качестве параметра, вы можете прочитать его следующим образом:

  1. Boolean(0) возвращает false
  2. Boolean(undefined) возвращает false
  3. Boolean({}) возвращает значение true, что означает, что он подталкивает его к возвращенному массиву
  4. Boolean(null) возвращает false
  5. Boolean('') возвращает false
  6. Boolean(true) возвращает true, что означает, что он подталкивает его к возвращенному массиву
  7. Boolean(5) возвращает true, что означает, что он подталкивает его к возвращенному массиву

поэтому общий процесс приведет к

[ {}, true, 5 ]

Другой простой пример

В этом примере используется одна и та же концепция передачи функции, которая принимает один аргумент

5,1
function startsWithLetterA(str) {
    if(str && str[0].toLowerCase() == 'a') {
        return true
    }
    return false;
}

var str              = 'Since Boolean is a native javascript function/constructor that takes [one optional paramater] and the filter method also takes a function and passes it the current array item as a parameter, you could read it like the following';
var strArray         = str.split(" ");
var wordsStartsWithA = strArray.filter(startsWithLetterA);
//["a", "and", "also", "a", "and", "array", "as"]

итерация

Традиционный for -loop

Традиционный for цикла состоит из трех компонентов:

  1. Инициализация: выполняется до того, как блок look будет выполнен в первый раз
  2. Условие: проверяет условие каждый раз до того, как выполняется цикл цикла, и завершает цикл, если false
  3. Последующая мысль: выполняется каждый раз после выполнения цикла

Эти три компонента отделены друг от друга a ; условное обозначение. Содержимое для каждого из этих трех компонентов является необязательным, что означает, что for минимального цикла возможно следующее:

for (;;) {
    // Do stuff
}

Конечно, вам нужно будет включить if(condition === true) { break; } или if(condition === true) { return; } где-то внутри, for -loop, чтобы остановить его.

Обычно, однако, инициализация используется для объявления индекса, это условие используется для сравнения этого индекса с минимальным или максимальным значением, а последующая мысль используется для увеличения индекса:

for (var i = 0, length = 10; i < length; i++) {
    console.log(i);
}

Использование традиционного for петли к петле через массив

Традиционный способ перебора массива состоит в следующем:

for (var i = 0, length = myArray.length; i < length; i++) {
    console.log(myArray[i]);
}

Или, если вы предпочитаете зацикливать назад, вы делаете это:

for (var i = myArray.length - 1; i > -1; i--) {
    console.log(myArray[i]);
}

Однако существует множество вариантов, например, таких как:

for (var key = 0, value = myArray[key], length = myArray.length; key < length; value = myArray[++key]) {
    console.log(value);
}

... или этот ...

var i = 0, length = myArray.length;
for (; i < length;) {
    console.log(myArray[i]);
    i++;
}

... или этот:

var key = 0, value;
for (; value = myArray[key++];){
    console.log(value);
}

Что лучше всего работает, в значительной степени зависит как от личного вкуса, так и от конкретного варианта использования, который вы реализуете.

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


В while цикл

Одна альтернатива for цикла является while цикл. Чтобы перебрать массив, вы можете сделать это:

var key = 0;
while(value = myArray[key++]){
    console.log(value);
}

Подобно традиционным for циклов, в while петли поддерживаются даже самым старым из браузеров.

Также обратите внимание, что цикл while может быть переписан как цикл for . Например, в while петля ведет себя здесь выше точно так же, как это for -loop:

for(var key = 0; value = myArray[key++];){
    console.log(value);
}

for...in

В JavaScript вы также можете сделать это:

for (i in myArray) {
    console.log(myArray[i]);
}

Однако это следует использовать с осторожностью, поскольку во всех случаях оно не ведет себя так же, как традиционный for цикла, и есть потенциальные побочные эффекты, которые необходимо учитывать. См. Почему используется «для ... в» с итерацией массива плохая идея? Больше подробностей.

for...of

В ES 6 цикл for-of loop является рекомендуемым способом итерации над значениями массива:

6
let myArray = [1, 2, 3, 4];
for (let value of myArray) {
  let twoValue = value * 2;
  console.log("2 * value is: %d", twoValue);
}

Следующий пример показывает разницу между for...of цикла , и for...in цикле:

6
let myArray = [3, 5, 7];
myArray.foo = "hello";

for (var i in myArray) {
  console.log(i); // logs 0, 1, 2, "foo"
}

for (var i of myArray) {
  console.log(i); // logs 3, 5, 7
}

Array.prototype.keys()

Метод Array.prototype.keys() может использоваться для итерации по таким показателям:

6
let myArray = [1, 2, 3, 4];
for (let i of myArray.keys()) {
  let twoValue = myArray[i] * 2;
  console.log("2 * value is: %d", twoValue);
}

Array.prototype.forEach()

Метод .forEach(...) является вариантом в ES 5 и выше. Он поддерживается всеми современными браузерами, а также Internet Explorer 9 и более поздними версиями.

5
[1, 2, 3, 4].forEach(function(value, index, arr) {
  var twoValue = value * 2;
  console.log("2 * value is: %d", twoValue);
});

Сравнивая с традиционным for цикла, мы не можем выпрыгнуть из цикла в .forEach() . В этом случае используйте цикл for или используйте частичную итерацию, представленную ниже.

Во всех версиях JavaScript, можно перебирать индексы массива , используя традиционный C-стиль for цикла.

var myArray = [1, 2, 3, 4];
for(var i = 0; i < myArray.length; ++i) {
  var twoValue = myArray[i] * 2;
  console.log("2 * value is: %d", twoValue);
}

Кроме того , можно использовать во while цикла:

var myArray = [1, 2, 3, 4],
    i = 0, sum = 0;
while(i++ < myArray.length) {
  sum += i;
}
console.log(sum);

Array.prototype.every

Начиная с ES5, если вы хотите итерировать часть массива, вы можете использовать Array.prototype.every , который выполняет Array.prototype.every до тех пор, пока мы не вернем false :

5
// [].every() stops once it finds a false result
// thus, this iteration will stop on value 7 (since 7 % 2 !== 0)
[2, 4, 7, 9].every(function(value, index, arr) {
  console.log(value);
  return value % 2 === 0; // iterate until an odd number is found
}); 

Эквивалент любой версии JavaScript:

var arr = [2, 4, 7, 9];
for (var i = 0; i < arr.length && (arr[i] % 2 !== 0); i++) { // iterate until an odd number is found
  console.log(arr[i]);
}

Array.prototype.some

Array.prototype.some пока мы не вернем true :

5
// [].some stops once it finds a false result
// thus, this iteration will stop on value 7 (since 7 % 2 !== 0)
[2, 4, 7, 9].some(function(value, index, arr) {
  console.log(value);
  return value === 7; // iterate until we find value 7
}); 

Эквивалент любой версии JavaScript:

var arr = [2, 4, 7, 9];
for (var i = 0; i < arr.length && arr[i] !== 7; i++) {
  console.log(arr[i]);
}

Библиотеки

Наконец, многие библиотеки утилиты также имеют свои собственные изменения foreach . Три из самых популярных из них:

jQuery.each() , в jQuery :

$.each(myArray, function(key, value) {
    console.log(value);
});

_.each() , в Underscore.js :

_.each(myArray, function(value, key, myArray) {
    console.log(value);
});

_.forEach() , в Lodash.js :

_.forEach(myArray, function(value, key) {
    console.log(value);
});

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

Фильтрация массивов объектов

Метод filter() принимает тестовую функцию и возвращает новый массив, содержащий только элементы исходного массива, которые передают предоставленный тест.

// Suppose we want to get all odd number in an array:
var numbers = [5, 32, 43, 4];
5,1
var odd = numbers.filter(function(n) {
  return n % 2 !== 0;
});
6
let odd = numbers.filter(n => n % 2 !== 0); // can be shortened to (n => n % 2)

odd будет содержать следующий массив: [5, 43] .

Он также работает с массивом объектов:

var people = [{
  id: 1,
  name: "John",
  age: 28
}, {
  id: 2,
  name: "Jane",
  age: 31
}, {
  id: 3,
  name: "Peter",
  age: 55
}];
5,1
var young = people.filter(function(person) {
  return person.age < 35;
});
6
let young = people.filter(person => person.age < 35);

young будет содержать следующий массив:

[{
  id: 1,
  name: "John",
  age: 28
}, {
  id: 2,
  name: "Jane",
  age: 31
}]

Вы можете выполнить поиск по всему массиву с таким значением:

var young = people.filter((obj) => {
  var flag = false;
  Object.values(obj).forEach((val) => {
    if(String(val).indexOf("J") > -1) {
      flag = true;
      return;
    }    
  });
  if(flag) return obj;
});

Это возвращает:

[{
  id: 1,
  name: "John",
  age: 28
},{
  id: 2,
  name: "Jane",
  age: 31
}]

Объединение элементов массива в строку

Чтобы объединить все элементы массива в строку, вы можете использовать метод join :

console.log(["Hello", " ", "world"].join("")); // "Hello world"
console.log([1, 800, 555, 1234].join("-")); // "1-800-555-1234"

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

Преобразование объектов массива в массивы

Что такое объекты типа Array?

JavaScript имеет «Array-подобные объекты», которые представляют собой представления объектов массивов с свойством length. Например:

var realArray = ['a', 'b', 'c'];
var arrayLike = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
};

Обычными примерами объектов типа Array являются объект arguments в функциях и HTMLCollection или NodeList возвращаемые из таких методов, как document.getElementsByTagName или document.querySelectorAll .

Однако одно ключевое различие между массивами и объектами, подобными массивам, заключается в том, что объекты типа Array наследуют от Object.prototype вместо Array.prototype . Это означает, что объекты, подобные Array, не могут получить доступ к общим прототипам Array, таким как forEach() , push() , map() , filter() и slice() :

var parent = document.getElementById('myDropdown');
var desiredOption = parent.querySelector('option[value="desired"]');
var domList = parent.children;

domList.indexOf(desiredOption); // Error! indexOf is not defined.
domList.forEach(function() { 
  arguments.map(/* Stuff here */) // Error! map is not defined.
}); // Error! forEach is not defined.

function func() {
  console.log(arguments);
}
func(1, 2, 3);   // → [1, 2, 3]

Преобразование объектов массива в массивы в ES6

  1. Array.from :
6
const arrayLike = {
  0: 'Value 0',
  1: 'Value 1',
  length: 2
};
arrayLike.forEach(value => {/* Do something */}); // Errors
const realArray = Array.from(arrayLike);
realArray.forEach(value => {/* Do something */}); // Works
  1. for...of :
6
var realArray = [];
for(const element of arrayLike) {
  realArray.append(element);
}
  1. Оператор распространения:
6
[...arrayLike]
  1. Object.values :
7
var realArray = Object.values(arrayLike);
  1. Object.keys :
6
var realArray = Object
   .keys(arrayLike)
   .map((key) => arrayLike[key]);

Преобразование объектов массива в массивы в ≤ ES5

Используйте Array.prototype.slice следующим образом:

var arrayLike = {
  0: 'Value 0',
  1: 'Value 1',
  length: 2
};
var realArray = Array.prototype.slice.call(arrayLike);
realArray = [].slice.call(arrayLike); // Shorter version

realArray.indexOf('Value 1'); // Wow! this works

Вы также можете использовать Function.prototype.call для вызова методов Array.prototype объектов, подобных Array, без их преобразования:

5,1
var domList = document.querySelectorAll('#myDropdown option');

domList.forEach(function() { 
  // Do stuff
}); // Error! forEach is not defined.

Array.prototype.forEach.call(domList, function() { 
  // Do stuff
}); // Wow! this works

Вы также можете использовать [].method.bind( arrayLikeObject ) чтобы заимствовать методы массива и glom их на свой объект:

5,1
var arrayLike = {
  0: 'Value 0',
  1: 'Value 1',
  length: 2
};

arrayLike.forEach(function() {
  // Do stuff
}); // Error! forEach is not defined.

[].forEach.bind(arrayLike)(function(val){
  // Do stuff with val
}); // Wow! this works

Изменение элементов во время преобразования

В ES6, используя Array.from , мы можем указать функцию карты, которая возвращает сопоставленное значение для создаваемого нового массива.

6
Array.from(domList, element => element.tagName); // Creates an array of tagName's

См. Раздел Массивы - объекты для детального анализа.

Уменьшение значений

5,1

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

Сумма массива

Этот метод можно использовать для уплотнения всех значений массива в одном значении:

[1, 2, 3, 4].reduce(function(a, b) {
  return a + b;
});
// → 10

Дополнительный второй параметр можно передать для reduce() . Его значение будет использоваться в качестве первого аргумента (указанного как a ) для первого вызова обратного вызова (заданного как function(a, b) ).

[2].reduce(function(a, b) {
  console.log(a, b); // prints: 1 2
  return a + b;
}, 1);
// → 3

5,1

Сгладить массив объектов

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

var array = [{
    key: 'one',
    value: 1
}, {
    key: 'two',
    value: 2
}, {
    key: 'three',
    value: 3
}];
5,1
array.reduce(function(obj, current) {
  obj[current.key] = current.value;
  return obj;
}, {});
6
array.reduce((obj, current) => Object.assign(obj, {
  [current.key]: current.value
}), {});
7
array.reduce((obj, current) => ({...obj, [current.key]: current.value}), {});

Обратите внимание, что Свойства Rest / Spread не входят в список готовых предложений ES2016 . ES2016 не поддерживается. Но мы можем использовать babel плагин babel-plugin-transform-object-rest-spread для его поддержки.

Все приведенные выше примеры для Flatten Array приводят к:

{
  one: 1,
  two: 2,
  three: 3
}

5,1

Использование карты Уменьшить

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

function map(list, fn) {
  return list.reduce(function(newList, item) {
    return newList.concat(fn(item));
  }, []);
}

// Usage:
map([1, 2, 3], function(n) { return n * n; });
// → [1, 4, 9]

Обратите внимание, что это только для иллюстрации (только параметра начального значения), используйте встроенную map для работы с преобразованиями списков (см. « Отображение значений для деталей»).


5,1

Найти минимальное или максимальное значение

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

var arr = [4, 2, 1, -10, 9]

arr.reduce(function(a, b) {
  return a < b ? a : b
}, Infinity);
// → -10
6

Найти уникальные значения

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

var arr = [1, 2, 1, 5, 9, 5];

arr.reduce((prev, number) => {
  if(prev.indexOf(number) === -1) {
    prev.push(number);
  }
  return prev;
}, []);
// → [1, 2, 5, 9]

Логическое связывание значений

5,1

.some и .every позволяют логически связывать значения массива.

В то время как .some сочетают возвращаемые значения с OR , .every объединяет их с AND .

Примеры .some

[false, false].some(function(value) {
  return value;
});
// Result: false

[false, true].some(function(value) {
  return value;
});
// Result: true

[true, true].some(function(value) {
  return value;
});
// Result: true

И примеры .every

[false, false].every(function(value) {
  return value;
});
// Result: false

[false, true].every(function(value) {
  return value;
});
// Result: false

[true, true].every(function(value) {
  return value;
});
// Result: true

Конкатенация массивов

Два массива

var array1 = [1, 2];
var array2 = [3, 4, 5];
3
var array3 = array1.concat(array2);  // returns a new array
6
var array3 = [...array1, ...array2]

Результаты в новом Array :

[1, 2, 3, 4, 5]

Несколько массивов

var array1 = ["a", "b"],
    array2 = ["c", "d"],
    array3 = ["e", "f"],
    array4 = ["g", "h"];
3

Предоставьте больше аргументов массива array.concat()

var arrConc = array1.concat(array2, array3, array4);
6

Предоставьте дополнительные аргументы []

var arrConc = [...array1, ...array2, ...array3, ...array4]

Результаты в новом Array :

["a", "b", "c", "d", "e", "f", "g", "h"]

Без копирования первого массива

var longArray = [1, 2, 3, 4, 5, 6, 7, 8],
    shortArray = [9, 10];
3

Предоставьте элементы shortArray качестве параметров для нажатия с помощью Function.prototype.apply shortArray

longArray.push.apply(longArray, shortArray);
6

Используйте оператор распространения, чтобы передать элементы shortArray качестве отдельных аргументов для push

longArray.push(...shortArray)

Значение longArray теперь:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Обратите внимание, что если второй массив слишком длинный (> 100 000 записей), вы можете получить ошибку переполнения стека (из-за того, как apply работы). Чтобы быть в безопасности, вы можете выполнять итерацию:

shortArray.forEach(function (elem) {
    longArray.push(elem);
});

Значения массива и без массива

var array = ["a", "b"];
3
var arrConc = array.concat("c", "d");
6
var arrConc = [...array, "c", "d"]

Результаты в новом Array :

["a", "b", "c", "d"]

Вы также можете смешивать массивы с не-массивами

var arr1 = ["a","b"];
var arr2 = ["e", "f"];

var arrConc = arr1.concat("c", "d", arr2);

Результаты в новом Array :

["a", "b", "c", "d", "e", "f"]

Добавить / Подготовить элементы к массиву

Unshift

Используйте .unshift для добавления одного или нескольких элементов в начале массива.

Например:

var array = [3, 4, 5, 6];
array.unshift(1, 2);

массив приводит к:

[1, 2, 3, 4, 5, 6]

От себя

Далее .push используется для добавления элементов после последнего текущего элемента.

Например:

var array = [1, 2, 3];
array.push(4, 5, 6);

массив приводит к:

[1, 2, 3, 4, 5, 6]

Оба метода возвращают новую длину массива.

Клавиши объектов и значения для массива

var object = {
    key1: 10,
    key2: 3,
    key3: 40,
    key4: 20
};
 
var array = [];
for(var people in object) {
  array.push([people, object[people]]);
}

Теперь массив

[
  ["key1", 10],
  ["key2", 3],
  ["key3", 40],
  ["key4", 20]
]

Сортировка многомерного массива

Учитывая следующий массив

var array = [
  ["key1", 10],
  ["key2", 3],
  ["key3", 40],
  ["key4", 20]
];

Вы можете отсортировать его по номеру (второй индекс)

array.sort(function(a, b) {
  return a[1] - b[1];
})
6
array.sort((a,b) => a[1] - b[1]);

Это приведет к выводу

[
  ["key2", 3],
  ["key1", 10],
  ["key4", 20],
  ["key3", 40]
]

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

Удаление элементов из массива

сдвиг

Используйте .shift для удаления первого элемента массива.

Например:

var array = [1, 2, 3, 4];
array.shift();

массив приводит к:

[2, 3, 4]

поп

Далее .pop используется для удаления последнего элемента из массива.

Например:

var array = [1, 2, 3];
array.pop();

массив приводит к:

[1, 2]

Оба метода возвращают удаленный элемент;

сращивание

Используйте .splice() чтобы удалить ряд элементов из массива. .splice() принимает два параметра, начальный индекс и необязательное количество элементов для удаления. Если второй параметр не .splice() удалит все элементы из начального индекса через конец массива.

Например:

var array = [1, 2, 3, 4];
array.splice(1, 2);

оставляет array , содержащий:

[1, 4]

Возврат array.splice() - это новый массив, содержащий удаленные элементы. В приведенном выше примере возврат будет следующим:

[2, 3]

Таким образом, опускание второго параметра эффективно разбивает массив на два массива с исходным окончанием до указанного индекса:

var array = [1, 2, 3, 4];
array.splice(2);

... оставляет array содержащий [1, 2] и возвращает [3, 4] .

удалять

Используйте delete для удаления элемента из массива без изменения длины массива:

var array = [1, 2, 3, 4, 5];
console.log(array.length); // 5
delete array[2];
console.log(array); // [1, 2, undefined, 4, 5]
console.log(array.length); // 5

Array.prototype.length

Присвоение значения length массива изменяет длину на заданное значение. Если новое значение меньше длины массива, элементы будут удалены с конца значения.

array = [1, 2, 3, 4, 5];
array.length = 2;
console.log(array); // [1, 2]

Реверсивные массивы

.reverse используется для изменения порядка элементов внутри массива.

Пример для .reverse :

[1, 2, 3, 4].reverse();

Результаты в:

[4, 3, 2, 1]

Примечание . Обратите внимание, что .reverse ( Array.prototype.reverse ) изменит массив на месте . Вместо того, чтобы возвращать обратную копию, он вернет тот же массив, обратный.

var arr1 = [11, 22, 33];
var arr2 = arr1.reverse();
console.log(arr2); // [33, 22, 11]
console.log(arr1); // [33, 22, 11]

Вы также можете перевернуть массив «глубоко»:

function deepReverse(arr) {
  arr.reverse().forEach(elem => {
    if(Array.isArray(elem)) {
      deepReverse(elem);
    }
  });
  return arr;
}

Пример для deepReverse:

var arr = [1, 2, 3, [1, 2, 3, ['a', 'b', 'c']]];

deepReverse(arr);

Результаты в:

arr // -> [[['c','b','a'], 3, 2, 1], 3, 2, 1]

Удалить значение из массива

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

array.filter(function(val) { return val !== to_remove; });

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

while(index = array.indexOf(3) !== -1) { array.splice(index, 1); }

И если вам нужно удалить только первое найденное значение, удалите цикл while:

var index = array.indexOf(to_remove);
if(index !== -1) { array.splice(index , 1); }

Проверка, является ли объект массивом

Array.isArray(obj) возвращает true если объект является Array , в противном случае - false .

Array.isArray([])           // true
Array.isArray([1, 2, 3])    // true
Array.isArray({})           // false
Array.isArray(1)            // false

В большинстве случаев вы можете instanceof проверить, является ли объект Array .

[] instanceof Array; // true
{} instanceof Array; // false

Array.isArray имеет преимущество перед использованием проверки instanceof в том, что он все равно вернет true даже если прототип массива был изменен и вернет false если прототип не-массивов был изменен на прототип Array .

var arr = [];
Object.setPrototypeOf(arr, null);
Array.isArray(arr);   // true
arr instanceof Array; // false

Сортировка массивов

Метод .sort() сортирует элементы массива. Метод по умолчанию будет сортировать массив в соответствии с строковыми кодами Unicode. Для сортировки массива численно метод .sort() должен иметь переданную ему функцию compareFunction .

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

По умолчанию Сортировать

Сортирует массив в порядке UNICODE.

['s', 't', 'a', 34, 'K', 'o', 'v', 'E', 'r', '2', '4', 'o', 'W', -1, '-4'].sort();

Результаты в:

[-1, '-4', '2', 34, '4', 'E', 'K', 'W', 'a', 'l', 'o', 'o', 'r', 's', 't', 'v']

Примечание: символы верхнего регистра переместились выше нижнего регистра. Массив не находится в алфавитном порядке, а цифры не имеют числового порядка.

Алфавитный порядок

['s', 't', 'a', 'c', 'K', 'o', 'v', 'E', 'r', 'f', 'l', 'W', '2', '1'].sort((a, b) => {
  return a.localeCompare(b);        
});

Результаты в:

['1', '2', 'a', 'c', 'E', 'f', 'K', 'l', 'o', 'r', 's', 't', 'v', 'W']

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

['s', 't', 'a', 'c', 'K', 1, 'v', 'E', 'r', 'f', 'l', 'o', 'W'].sort((a, b) => {
  return a.toString().localeCompare(b);      
});

Сортировка строк по длине (с наибольшей длиной)

["zebras", "dogs", "elephants", "penguins"].sort(function(a, b) {
  return b.length - a.length;
});

Результаты в

["elephants", "penguins", "zebras", "dogs"];

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

["zebras", "dogs", "elephants", "penguins"].sort(function(a, b) {
  return a.length - b.length;
});

Результаты в

["dogs", "zebras", "penguins", "elephants"];

Численное Сортировка (по возрастанию)

[100, 1000, 10, 10000, 1].sort(function(a, b) {
  return a - b;
});

Результаты в:

[1, 10, 100, 1000, 10000]

Численное Сортировка (по убыванию)

[100, 1000, 10, 10000, 1].sort(function(a, b) {
  return b - a;
});

Результаты в:

[10000, 1000, 100, 10, 1]

Сортировка массива четными и нечетными числами

[10, 21, 4, 15, 7, 99, 0, 12].sort(function(a, b) {
    return (a & 1) - (b & 1) || a - b;
});

Результаты в:

[0, 4, 10, 12, 7, 15, 21, 99]

Дата Сортировка (по убыванию)

var dates = [
  new Date(2007, 11, 10),
  new Date(2014, 2, 21),
  new Date(2009, 6, 11),
  new Date(2016, 7, 23)
];

dates.sort(function(a, b) {
  if (a > b) return -1;
  if (a < b) return 1;
  return 0;
});

// the date objects can also sort by its difference
// the same way that numbers array is sorting
dates.sort(function(a, b) {
  return b-a;
});

Результаты в:

[
  "Tue Aug 23 2016 00:00:00 GMT-0600 (MDT)",
  "Fri Mar 21 2014 00:00:00 GMT-0600 (MDT)",
  "Sat Jul 11 2009 00:00:00 GMT-0600 (MDT)",
  "Mon Dec 10 2007 00:00:00 GMT-0700 (MST)"
]

Неглубокое клонирование массива

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

Чтобы неглубоко клонировать массив (т. Е. Иметь новый экземпляр массива, но с теми же элементами), вы можете использовать следующий однострочный:

var clone = arrayToClone.slice();

Это вызывает встроенный метод JavaScript Array.prototype.slice . Если вы передадите аргументы на slice , вы можете получить более сложные поведения, которые создают неглубокие клоны только части массива, но для наших целей просто вызов slice() создаст мелкую копию всего массива.

Весь метод, используемый для преобразования массива типа объектов в массив , применим для клонирования массива:

6
arrayToClone = [1, 2, 3, 4, 5];
clone1 = Array.from(arrayToClone);
clone2 = Array.of(...arrayToClone);
clone3 = [...arrayToClone] // the shortest way
5,1
arrayToClone = [1, 2, 3, 4, 5];
clone1 = Array.prototype.slice.call(arrayToClone);
clone2 = [].slice.call(arrayToClone);

Поиск массива

Рекомендуемый способ (с ES5) использовать Array.prototype.find :

let people = [
  { name: "bob" },
  { name: "john" }
];

let bob = people.find(person => person.name === "bob");

// Or, more verbose
let bob = people.find(function(person) {
  return person.name === "bob";
});

В любой версии JavaScript может использоваться стандарт for цикла:

for (var i = 0; i < people.length; i++) {
  if (people[i].name === "bob") {
    break; // we found bob
  }
}

FindIndex

Метод findIndex () возвращает индекс в массиве, если элемент в массиве удовлетворяет предоставленной функции тестирования. В противном случае возвращается -1.

array = [
  { value: 1 },
  { value: 2 },
  { value: 3 },
  { value: 4 },
  { value: 5 }
];
var index = array.findIndex(item => item.value === 3); // 2
var index = array.findIndex(item => item.value === 12); // -1

Удаление / Добавление элементов с помощью splice ()

Метод splice() может использоваться для удаления элементов из массива. В этом примере мы удалим первые 3 из массива.

var values = [1, 2, 3, 4, 5, 3];
var i = values.indexOf(3);
if (i >= 0) {
  values.splice(i, 1);
}
// [1, 2, 4, 5, 3]

Метод splice() также может использоваться для добавления элементов в массив. В этом примере мы вставляем числа 6, 7 и 8 в конец массива.

var values = [1, 2, 4, 5, 3];
var i = values.length + 1;
values.splice(i, 0, 6, 7, 8);
//[1, 2, 4, 5, 3, 6, 7, 8]

Первый аргумент метода splice() - это индекс для удаления / вставки элементов. Второй аргумент - количество удаляемых элементов. Третий аргумент и вперед - это значения, которые нужно вставить в массив.

Сравнение массивов

Для простого сравнения массивов вы можете использовать JSON stringify и сравнивать выходные строки:

JSON.stringify(array1) === JSON.stringify(array2)

Обратите внимание: это будет работать, только если оба объекта являются сериализуемыми JSON и не содержат циклических ссылок. Это может вызвать TypeError: Converting circular structure to JSON

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

function compareArrays(array1, array2) { 
  var i, isA1, isA2;
  isA1 = Array.isArray(array1);
  isA2 = Array.isArray(array2);
  
  if (isA1 !== isA2) { // is one an array and the other not?
    return false;      // yes then can not be the same
  }
  if (! (isA1 && isA2)) {      // Are both not arrays 
    return array1 === array2;  // return strict equality
  }
  if (array1.length !== array2.length) { // if lengths differ then can not be the same
    return false;
  }
  // iterate arrays and compare them
  for (i = 0; i < array1.length; i += 1) {
    if (!compareArrays(array1[i], array2[i])) { // Do items compare recursively
      return false;
    }           
  }
  return true; // must be equal
}

ПРЕДУПРЕЖДЕНИЕ. Использование вышеуказанной функции является опасным и должно быть завернуто в try catch если вы подозреваете, что есть вероятность, что массив имеет циклические ссылки (ссылка на массив, содержащий ссылку на себя)

a = [0] ;
a[1] = a;
b = [0, a]; 
compareArrays(a, b); // throws RangeError: Maximum call stack size exceeded

Примечание . Функция использует оператор строгого равенства === для сравнения элементов без массива {a: 0} === {a: 0} является false

Разрушение массива

6

При назначении новой переменной массив может быть разрушен.

const triangle = [3, 4, 5];
const [length, height, hypotenuse] = triangle;

length === 3;     // → true
height === 4;     // → true
hypotneuse === 5; // → true

Элементы могут быть пропущены

const [,b,,c] = [1, 2, 3, 4];

console.log(b, c); // → 2, 4

Оператор отдыха может использоваться также

const [b,c, ...xs] = [2, 3, 4, 5];
console.log(b, c, xs); // → 2, 3, [4, 5]

Массив также может быть разрушен, если это аргумент функции.

function area([length, height]) {
  return (length * height) / 2;
}

const triangle = [3, 4, 5];

area(triangle); // → 6

Обратите внимание, что третий аргумент не указан в функции, потому что он не нужен.

Подробнее о деструктивном синтаксисе ...

Удаление повторяющихся элементов

Начиная с ES5.1, вы можете использовать собственный метод Array.prototype.filter для циклического прохождения массива и оставить только записи, которые передают заданную функцию обратного вызова.

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

5,1
var uniqueArray = ['a', 1, 'a', 2, '1', 1].filter(function(value, index, self) { 
  return self.indexOf(value) === index;
}); // returns ['a', 1, 2, '1']

Если ваша среда поддерживает ES6, вы также можете использовать объект Set . Этот объект позволяет хранить уникальные значения любого типа, будь то примитивные значения или ссылки на объекты:

6
var uniqueArray = [... new Set(['a', 1, 'a', 2, '1', 1])];

См. Также следующие ответы на SO:

Удаление всех элементов

var arr = [1, 2, 3, 4];

Способ 1

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

arr = [];

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

Пример утечки памяти из-за плохой очистки массива:

var count = 0;

function addListener(arr) { // arr is closed over
  var b = document.body.querySelector("#foo" + (count++));
  b.addEventListener("click", function(e) { // this functions reference keeps
    // the closure current while the
    // event is active
    // do something but does not need arr       
  });
}

arr = ["big data"];
var i = 100;
while (i > 0) {
  addListener(arr); // the array is passed to the function
  arr = []; // only removes the reference, the original array remains
  array.push("some large data"); // more memory allocated
  i--;
}
// there are now 100 arrays closed over, each referencing a different array
// no a single item has been deleted

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

Способ 2

Установка свойства length удаляет весь элемент массива из новой длины массива в длину старого массива. Это самый эффективный способ удаления и разыменования всех элементов в массиве. Сохраняет ссылку на исходный массив

arr.length = 0;

Способ 3

Подобно методу 2, но возвращает новый массив, содержащий удаленные элементы. Если вам не нужны элементы, этот метод неэффективен, так как новый массив все еще создается только для немедленного разыменования.

arr.splice(0); // should not use if you don't want the removed items
// only use this method if you do the following
var keepArr = arr.splice(0); // empties the array and creates a new array containing the
                             // removed items

Связанный с этим вопрос .

Использование карты для переформатирования объектов в массиве

Array.prototype.map() : возвращает новый массив с результатами вызова предоставленной функции для каждого элемента исходного массива.

Следующий пример кода принимает массив лиц и создает новый массив, содержащий людей с свойством 'fullName'

var personsArray = [
  {
    id: 1,
    firstName: "Malcom",
    lastName: "Reynolds"
  }, {
    id: 2,
    firstName: "Kaylee",
    lastName: "Frye"
  }, {
    id: 3,
    firstName: "Jayne",
    lastName: "Cobb"
  }
];

// Returns a new array of objects made up of full names.
var reformatPersons = function(persons) {
  return persons.map(function(person) {
    // create a new object to store full name.
    var newObj = {};
    newObj["fullName"] = person.firstName + " " + person.lastName;

    // return our new object.
    return newObj;
  });
};

Теперь мы можем назвать reformatPersons(personsArray) и получить новый массив только полных имен каждого человека.

var fullNameArray = reformatPersons(personsArray);
console.log(fullNameArray);
/// Output
[
  { fullName: "Malcom Reynolds" }, 
  { fullName: "Kaylee Frye" },
  { fullName: "Jayne Cobb" }
]

personsArray и его содержимое остаются неизменными.

console.log(personsArray);
/// Output
[
  {
    firstName: "Malcom",
    id: 1,
    lastName: "Reynolds"
  }, {
    firstName: "Kaylee",
    id: 2,
    lastName: "Frye"
  }, {
    firstName: "Jayne",
    id: 3,
    lastName: "Cobb"
  }
]

Объединить два массива в качестве пары ключевых значений

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

var columns = ["Date", "Number", "Size", "Location", "Age"];
var rows = ["2001", "5", "Big", "Sydney", "25"];
var result =  rows.reduce(function(result, field, index) {
  result[columns[index]] = field;
  return result;
}, {})

console.log(result);

Выход:

{
  Date: "2001",
  Number: "5",
  Size: "Big",
  Location: "Sydney",
  Age: "25"
}

Преобразование строки в массив

Метод .split() разбивает строку на массив подстрок. По умолчанию .split() сломает строку на подстроки на пространствах ( " " ), что эквивалентно вызову .split(" ") .

Параметр, переданный в .split() указывает символ или регулярное выражение для использования для разделения строки.

.split строку на массив .split с пустой строкой ( "" ). Важное примечание. Это работает только в том случае, если все ваши персонажи соответствуют символам нижнего диапазона Юникода, который охватывает большинство английских и большинства европейских языков. Для языков, которым требуются символы символа Unicode длиной 3 и 4 байта, slice("") будет разделять их.

var strArray = "StackOverflow".split("");
// strArray = ["S", "t", "a", "c", "k", "O", "v", "e", "r", "f", "l", "o", "w"]
6

Используя оператор spread ( ... ), преобразуем string в array .

var strArray = [..."sky is blue"];        
// strArray = ["s", "k", "y", " ", "i", "s", " ", "b", "l", "u", "e"]

Проверить все элементы массива для равенства

.every метод проверяет, проходят ли все элементы массива предоставленный предикатный тест.

Чтобы проверить все объекты на равенство, вы можете использовать следующие фрагменты кода.

[1, 2, 1].every(function(item, i, list) { return item === list[0]; }); // false
[1, 1, 1].every(function(item, i, list) { return item === list[0]; }); // true
6
[1, 1, 1].every((item, i, list) => item === list[0]); // true

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

let data = [
  { name: "alice", id: 111 },
  { name: "alice", id: 222 }
];

data.every(function(item, i, list) { return item === list[0]; }); // false
data.every(function(item, i, list) { return item.name === list[0].name; }); // true
6
data.every((item, i, list) => item.name === list[0].name); // true

Скопировать часть массива

Метод slice () возвращает копию части массива.

Он принимает два параметра: arr.slice([begin[, end]]) :

начать

Нулевой индекс, который является началом извлечения.

конец

Индекс, основанный на нулевом индексе, который является окончанием извлечения, нарезанный до этого индекса, но он не включен.

Если конец отрицательного числа, end = arr.length + end .

Пример 1

// Let's say we have this Array of Alphabets
var arr = ["a", "b", "c", "d"...];

// I want an Array of the first two Alphabets
var newArr = arr.slice(0, 2); // newArr === ["a", "b"]

Пример 2.

// Let's say we have this Array of Numbers
// and I don't know it's end
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9...];

// I want to slice this Array starting from
// number 5 to its end
var newArr = arr.slice(4); // newArr === [5, 6, 7, 8, 9...]

Поиск минимального или максимального элемента

Если ваш массив или подобный массиву объект является числовым , то есть, если все его элементы являются числами, вы можете использовать Math.min.apply или Math.max.apply , передав null в качестве первого аргумента, а ваш массив - вторым ,

var myArray = [1, 2, 3, 4];

Math.min.apply(null, myArray); // 1
Math.max.apply(null, myArray); // 4
6

В ES6 вы можете использовать оператор ... для распространения массива и принятия минимального или максимального элемента.

var myArray = [1, 2, 3, 4, 99, 20];

var maxValue = Math.max(...myArray); // 99
var minValue = Math.min(...myArray); // 1

В следующем примере используется цикл for :

var maxValue = myArray[0];
for(var i = 1; i < myArray.length; i++) {
   var currentValue = myArray[i];
   if(currentValue > maxValue) {
      maxValue = currentValue;
   }
}
5,1

Следующий пример использует Array.prototype.reduce() чтобы найти минимум или максимум:

var myArray = [1, 2, 3, 4];

myArray.reduce(function(a, b) {
  return Math.min(a, b);
}); // 1

myArray.reduce(function(a, b) {
  return Math.max(a, b);
}); // 4
6

или используя функции стрелок:

myArray.reduce((a, b) => Math.min(a, b)); // 1
myArray.reduce((a, b) => Math.max(a, b)); // 4
5,1

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

function myMax(array) {
  return array.reduce(function(maxSoFar, element) {
    return Math.max(maxSoFar, element);
  }, -Infinity);
}

myMax([3, 5]);             // 5
myMax([]);                 // -Infinity
Math.max.apply(null, []);  // -Infinity

Подробнее о том, как правильно использовать reduce см. « Уменьшение значений» .

Сглаживание массивов

2 размерных массива

6

В ES6 мы можем сгладить массив оператором распространения ... :

function flattenES6(arr) {
  return [].concat(...arr);
}

var arrL1 = [1, 2, [3, 4]];
console.log(flattenES6(arrL1)); // [1, 2, 3, 4]
5

В ES5 мы можем добиться этого с помощью .apply () :

function flatten(arr) {
  return [].concat.apply([], arr);
}

var arrL1 = [1, 2, [3, 4]];
console.log(flatten(arrL1)); // [1, 2, 3, 4]

Массивы большего размера

Учитывая глубоко вложенный массив, подобный

var deeplyNested = [4,[5,6,[7,8],9]];

Он может быть сплющен этой магией

console.log(String(deeplyNested).split(',').map(Number);
#=> [4,5,6,7,8,9]

Или же

const flatten = deeplyNested.toString().split(',').map(Number)
console.log(flatten);
#=> [4,5,6,7,8,9]

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

Вставка элемента в массив по определенному индексу

Простая вставка элемента может быть выполнена с Array.prototype.splice метода Array.prototype.splice :

arr.splice(index, 0, item);

Более продвинутый вариант с несколькими аргументами и поддержкой цепочки:

/* Syntax:
   array.insert(index, value1, value2, ..., valueN) */

Array.prototype.insert = function(index) {
  this.splice.apply(this, [index, 0].concat(
    Array.prototype.slice.call(arguments, 1)));
  return this;
};

["a", "b", "c", "d"].insert(2, "X", "Y", "Z").slice(1, 6);  // ["b", "X", "Y", "Z", "c"]

И с объединением массива и поддержкой цепочек:

/* Syntax:
   array.insert(index, value1, value2, ..., valueN) */

Array.prototype.insert = function(index) {
  index = Math.min(index, this.length);
  arguments.length > 1
    && this.splice.apply(this, [index, 0].concat([].pop.call(arguments)))
    && this.insert.apply(this, arguments);
  return this;
};

["a", "b", "c", "d"].insert(2, "V", ["W", "X", "Y"], "Z").join("-");  // "a-b-V-W-X-Y-Z-c-d"

Метод entries ()

Метод entries() возвращает новый объект Array Iterator, содержащий пары ключ / значение для каждого индекса в массиве.

6
var letters = ['a','b','c'];

for(const[index,element] of letters.entries()){
  console.log(index,element);
}

результат

0 "a"
1 "b"
2 "c"

Примечание . Этот метод не поддерживается в Internet Explorer.

Части этого контента от Array.prototype.entries от Mozilla Авторы, лицензированные по CC-by-SA 2.5



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow