Как я могу преобразовать объект «arguments» в массив в JavaScript? - PullRequest
417 голосов
/ 07 июня 2009

Объект arguments в JavaScript является странной бородавкой - в большинстве случаев он действует как массив, но на самом деле это не объект массива. Поскольку это на самом деле что-то совсем другое , он не имеет полезных функций из Array.prototype, таких как forEach, sort, filter и map.

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

function sortArgs() {
    var args = [];
    for (var i = 0; i < arguments.length; i++)
        args[i] = arguments[i];
    return args.sort();
}

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

Ответы [ 21 ]

687 голосов
/ 07 июня 2009

ES6 с использованием остальных параметров

Если вы можете использовать ES6, вы можете использовать:

Параметры покоя

function sortArgs(...args) {
  return args.sort(function (a, b) { return a - b; });
}

document.body.innerHTML = sortArgs(12, 4, 6, 8).toString();

Как вы можете прочитать по ссылке

Синтаксис параметра rest позволяет нам представлять неопределенное количество аргументов в виде массива.

Если вам интересен синтаксис ..., он называется Оператор распространения , и вы можете прочитать больше здесь .

ES6 с использованием Array.from ()

Использование Array.from :

function sortArgs() {
  return Array.from(arguments).sort(function (a, b) { return a - b; });
}

document.body.innerHTML = sortArgs(12, 4, 6, 8).toString();

Array.from просто преобразуйте объекты типа Array или Iterable в экземпляры Array.



ES5

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

function sortArgs() {
    var args = Array.prototype.slice.call(arguments);
    return args.sort();
}

Почему это работает? Вот отрывок из самой документации ECMAScript 5 :

ПРИМЕЧАНИЕ : функция slice специально сделана не привязанной к типу; он не требует, чтобы его значение this было объектом Array. Поэтому его можно передавать другим объектам для использования в качестве метода. Возможность успешного применения функции slice к хост-объекту зависит от реализации.

Следовательно, slice работает на всем, что имеет свойство length, что удобно делать arguments.


Если Array.prototype.slice слишком много для вас, вы можете немного его сократить, используя литералы массива:

var args = [].slice.call(arguments);

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

38 голосов
/ 03 июня 2014

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

function doesntLeakArguments() {
    var args = new Array(arguments.length);
    for(var i = 0; i < args.length; ++i) {
        args[i] = arguments[i];
    }
    return args;
}

Этот метод используется в пользу var args = [].slice.call(arguments);. Автор также показывает, как шаг сборки может помочь уменьшить детализацию.

28 голосов
/ 09 июня 2009
function sortArgs(){ return [].slice.call(arguments).sort() }

// Returns the arguments object itself
function sortArgs(){ return [].sort.call(arguments) }

Некоторые методы массива специально созданы, чтобы не требовать, чтобы целевой объект был фактическим массивом. Они только требуют, чтобы у цели было свойство с именем length и индексами (которые должны быть целыми или равными нулю или больше).

[].sort.call({0:1, 1:0, length:2}) // => ({0:0, 1:1, length:2})
12 голосов
/ 27 октября 2013

Использование:

function sortArguments() {
  return arguments.length === 1 ? [arguments[0]] :
                 Array.apply(null, arguments).sort();
}

Array(arg1, arg2, ...) возврат [arg1, arg2, ...]

Array(str1) возвращает [str1]

Array(num1) возвращает массив, содержащий num1 элементов

Вы должны проверить количество аргументов!

Array.slice версия (медленнее):

function sortArguments() {
  return Array.prototype.slice.call(arguments).sort();
}

Array.push версия (медленнее, быстрее, чем срез):

function sortArguments() {
  var args = [];
  Array.prototype.push.apply(args, arguments);
  return args.sort();
}

Переместить версию (медленнее, но маленький размер быстрее):

function sortArguments() {
  var args = [];
  for (var i = 0; i < arguments.length; ++i)
    args[i] = arguments[i];
  return args.sort();
}

Array.concat версия (самая медленная):

function sortArguments() {
  return Array.prototype.concat.apply([], arguments).sort();
}
9 голосов
/ 07 июня 2009

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

function sortArgs(){
  return $.makeArray(arguments).sort();
}
6 голосов
/ 24 января 2016

В ECMAScript 6 нет необходимости использовать уродливые хаки, такие как Array.prototype.slice(). Вместо этого вы можете использовать синтаксис распространения (...) .

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

Это может выглядеть странно, но довольно просто. Он просто извлекает arguments 'элементы и помещает их обратно в массив. Если вы все еще не понимаете, посмотрите следующие примеры:

console.log([1, ...[2, 3], 4]);
console.log([...[1, 2, 3]]);
console.log([...[...[...[1]]]]);

Обратите внимание, что он не работает в некоторых старых браузерах, таких как IE 11, поэтому, если вы хотите поддерживать эти браузеры, вы должны использовать Babel .

5 голосов
/ 03 июля 2013

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

На мой взгляд, лучшее решение для небольшого количества аргументов:

function sortArgs (){
  var q = [];
  for (var k = 0, l = arguments.length; k < l; k++){
    q[k] = arguments[k];
  }
  return q.sort();
}

Для других случаев:

function sortArgs (){ return Array.apply(null, arguments).sort(); }
4 голосов
/ 26 января 2016

Я рекомендую использовать ECMAScript 6 оператор распространения , который будет привязывать конечные параметры к массиву. С этим решением вам не нужно прикасаться к объекту arguments, и ваш код будет упрощен. Недостатком этого решения является то, что оно не работает в большинстве браузеров, поэтому вместо этого вам придется использовать JS-компилятор, такой как Babel. Под капотом Бабель превращает arguments в массив с циклом for.

function sortArgs(...args) {
  return args.sort();
}

Если вы не можете использовать ECMAScript 6, я рекомендую взглянуть на некоторые другие ответы, такие как @Jonathan Fingland

function sortArgs() {
    var args = Array.prototype.slice.call(arguments);
    return args.sort();
}
4 голосов
/ 05 октября 2016

Lodash:

var args = _.toArray(arguments);

в действии:

(function(){ console.log(_.toArray(arguments).splice(1)); })(1, 2, 3)

производит:

[2,3]
4 голосов
/ 26 января 2016

Используйте Array.from(), который принимает объект в виде массива (такой как arguments) в качестве аргумента и преобразует его в массив:

(function() {
  console.log(Array.from(arguments));
}(1, 2, 3));

Обратите внимание, что он не работает в некоторых старых браузерах, таких как IE 11, поэтому, если вы хотите поддерживать эти браузеры, вы должны использовать Babel .

...