JavaScriptで「arguments」オブジェクトを配列に変換するにはどうすればよいですか?


433

argumentsJavaScript のオブジェクトは奇妙なイボです。ほとんどの状況で配列のように動作しますが、実際には配列オブジェクトではありません。それはですので、完全には本当に何か他のもの、それはからの便利な機能を持っていないArray.prototypeようなforEachsortfilter、とmap

単純なforループを使用して、argumentsオブジェクトから新しい配列を作成するのは簡単です。たとえば、次の関数は引数を並べ替えます。

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

ただし、これは、非常に便利なJavaScript配列関数にアクセスするためだけに実行する必要がある、かなり哀れなことです。標準ライブラリを使用して行う組み込みの方法はありますか?


回答:


725

ES6でレストパラメータを使用する

ES6を使用できる場合は、以下を使用できます。

残りのパラメータ

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

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

リンクで読めるように

残りのパラメータ構文により、不特定の数の引数を配列として表すことができます。

...構文に興味がある場合は、Spread Operatorと呼ばれます。詳しくは、こちらをご覧ください

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-likeまたはIterableオブジェクトをArrayインスタンスに変換するだけです。



ES5

引数オブジェクトで実際にArrayslice関数を使用するだけで、それを標準のJavaScript配列に変換できます。Arrayのプロトタイプを使用して手動で参照する必要があります。

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

なぜこれが機能するのですか?ええと、ECMAScript 5のドキュメント自体からの抜粋です

slice関数は意図的に一般的です。この値がArrayオブジェクトである必要はありません。したがって、メソッドとして使用するために他の種類のオブジェクトに転送できます。slice関数をホストオブジェクトに正常に適用できるかどうかは、実装によって異なります。

したがって、便利なプロパティsliceを持つすべてのものに作用します。lengtharguments


Array.prototype.sliceが一口になりすぎている場合は、配列リテラルを使用して少し省略できます。

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

ただし、前のバージョンの方が明示的であると感じる傾向があるため、代わりにそれを使用したいと思います。配列リテラル表記の乱用は、ハックに感じられ、奇妙に見えます。


5
最近のFirefoxバージョン(2.0?)とECMAScript 5では、これを少し簡単にするArray.sliceメソッドがあります。次のように呼び出します:var arge = Array.slice(arguments、0);。
マシュークルムリー

9
何の0ため?渡す引数がないので、なぜ使用できないのですvar args = Array.prototype.slice.call(arguments);か?[ MDC引数ページ ](developer.mozilla.org/en/JavaScript/Reference/…)は、なしのメソッドを提案してい0ます。
Peter Ajtai

3
@Barney-元の質問が引数をソートする必要があるため、ソートが必要です。配列に変換したいだけの場合は必要ありません。
Krease 2013

17
「JavaScriptエンジン(V8など)での最適化が妨げられるため、引数をスライスしないでください。」- MDNからdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
frameworkninja

3
それが元の質問に答えているかどうかはわかりません。時間が経ちました。ES6は、FirefoxとChromeで実験して、残りのパラメータは -良い代替になってきているfunction sortArgs(...argsToSort) { return argsToSort.sort(); }MDNからdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
キールKanos

40

V8 JavaScriptエンジンで関数を最適化できるようにオブジェクトを配列に管理する方法を示す、このBluebird promiseライブラリwikiページを参照することも価値argumentsがあります。

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);ます。著者はまた、ビルドステップが冗長性を減らすのにどのように役立つかを示しています。


2
+1とBluebird Optimization Killerページへのリンクに感謝します。PS:node-thunkifyプロジェクトでこの最適化が使用されているのを最近見ました。
Yves M.

29
function sortArgs(){ return [].slice.call(arguments).sort() }

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

一部の配列メソッドは、ターゲットオブジェクトが実際の配列である必要がないように意図的に作成されています。ターゲットに必要なのは、長さとインデックス(ゼロ以上の整数である必要があります)という名前のプロパティのみです。

[].sort.call({0:1, 1:0, length:2}) // => ({0:0, 1:1, length:2})

12

使用する:

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();
}

1
Array.concatのフラット化動作のため、配列引数を受け入れることに注意してください。sortArguments(2、[3,0]、1)は0,1,2,3を返します。
Hafthor

9

jQueryを使用している場合、以下は、私の意見ではかなり覚えやすくなっています。

function sortArgs(){
  return $.makeArray(arguments).sort();
}

1
それは本質的に私が純粋なJSで探していたものですが、jQueryによってJSが少し簡単に理解できるようにする確かな例を+1します。
Andrew Coleson、2009年

2
「フレームワーク/ライブラリーの別のタグも含まれていない限り、純粋なJavaScriptの回答が期待されます。」
のMichałPerłakowski

6

ECMAScript 6では、のような醜いハックを使用する必要はありませんArray.prototype.slice()。代わりに、spread構文(...)を使用できます

(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

以下は、引数を配列に変換するいくつかの方法のベンチマークです。

私の場合、引数が少ない場合の最善の解決策は次のとおりです。

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(); }

ベンチマークの場合は+1。現在のグラフでsortArgsは、Firefoxでは6倍高速ですが、最新のChromeでは2倍低速Array.applyです。
joeytwiddle 2013

1
JS V8エンジンの最適化を妨げるArray.prototype.sliceは廃止予定なので、ES6が広く利用できるようになるまで、これが最良のソリューションであると考えています+1
Sasha

1
さらに、Array.slice()のようなArrayジェネリックスメソッドも廃止されました
Sasha

4

ECMAScript 6 スプレッドオペレーターを使用することをお勧めします。これは、トレーリングパラメーターを配列にバインドします。このソリューションを使用すると、argumentsオブジェクトに触れる必要がなく、コードが簡略化されます。このソリューションの欠点は、ほとんどのブラウザーでは機能しないため、代わりにBabelなどの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

ロダッシュ:

var args = _.toArray(arguments);

動作中:

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

生成する:

[2,3]

6
なんで_.toArray
Menixator 2016年

5
しかし_.toArray、より適切です。
Menixator 2016年

いくつかの主要な引数を削除したい場合が多いので、_。sliceがより適切であると私は主張します。
Hafthor、

4

を使用してArray.from()、配列のようなオブジェクト(などarguments)を引数として受け取り、配列に変換します。

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

IE 11などの一部の古いブラウザーでは機能しないことに注意してください。これらのブラウザーをサポートする場合は、Babelを使用する必要があります。


3
function sortArg(){
var args = Array.from(arguments); return args.sort();
}

 function sortArg(){
    var args = Array.from(arguments); 
    return args.sort();
    }
 
 console.log(sortArg('a', 'b', 1, 2, '34', 88, 20, '19', 39, 'd', 'z', 'ak', 'bu', 90));


1

別の答え。

ブラックマジックスペルを使用する:

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

Firefox、Chrome、Node.js、IE11は問題ありません。


6
これは間違いなく最良の解決策です...コードを完全に読めなくしたい場合。また、__proto__非推奨です。MDN docsを参照してください。
のMichałPerłakowski

1

使ってみてください Object.setPrototypeOf()

説明:セットprototypeargumentsArray.prototype

function toArray() {
  return Object.setPrototypeOf(arguments, Array.prototype)
} 

console.log(toArray("abc", 123, {def:456}, [0,[7,[14]]]))


説明:の各インデックスを取りarguments、アイテムを配列の対応するインデックスの配列に配置します。

代わりに使用できます Array.prototype.map()

function toArray() {
  return [].map.call(arguments, (_,k,a) => a[k])
} 

console.log(toArray("abc", 123, {def:456}, [0,[7,[14]]]))


説明:の各インデックスを取りarguments、アイテムを配列の対応するインデックスの配列に配置します。

for..of ループ

function toArray() {
 let arr = []; for (let prop of arguments) arr.push(prop); return arr
} 

console.log(toArray("abc", 123, {def:456}, [0,[7,[14]]]))


または Object.create()

説明:オブジェクトを作成し、オブジェクトのプロパティをの各インデックスでアイテムに設定しますargumentsprototype作成されたオブジェクトのセットArray.prototype

function toArray() {
  var obj = {};
  for (var prop in arguments) {
    obj[prop] = {
      value: arguments[prop],
      writable: true,
      enumerable: true,
      configurable: true
    }
  } 
  return Object.create(Array.prototype, obj);
}

console.log(toArray("abc", 123, {def: 456}, [0, [7, [14]]]))


あなたはあなたの答えが「長い答え」についての質問の下の警告を満たすかどうか人々に尋ねてきました。私にはあなたの答えの主な問題は、あなたがここに示す方法のいずれかを使用する必要がある理由を説明しないことです。あなたが提案した解決策はどれも、受け入れられた回答の解決策よりも悪いので、私が使う方法はありません。たとえば、のドキュメントへの参照Object.setPrototypeOfは、それが「非常に遅い操作」であることを警告しています。なぜ私はこれをArray.prototype.slice.call何度も使用するのですか?
ルイ

@Louisが各アプローチの説明を含む回答を更新しました。OPでの質問は「標準ライブラリを使用して行う組み込みの方法はありますか?」のようです。、組み込みの「なぜメソッドを使用する必要があるのか​​」ではありませんか?回答を投稿したユーザーは、投稿されたソリューションがOPに「適切」であるかどうかをどのように正確に判断できますか?これを決定するのはOPの責任だと思われますか?実際、通知のこの部分は、このユーザーが関心を持っているものです:「あなたの答えが正しい理由を説明してください」。この質問に提供された回答のいずれかは、「この回答は「正しい」ので、x、y、z」と述べていますか?
guest271314 2016

私が説明したのは、SOが一般的にどのように機能するかです。SOに対して投稿された質問はにOPのためではなく、質問とその回答を後で読む何十万人もの人々のためであるため、OPが1つのソリューションが他のソリューションよりも優れている理由を知りたいかどうかはまったく無関係です。また、回答に投票する人は、OPが満足する可能性のあるものに従って投票する必要はありません。
Louis

1

クリーンで簡潔なソリューションを次に示します。

function argsToArray() {
  return Object.values(arguments);
}

// example usage
console.log(
  argsToArray(1, 2, 3, 4, 5)
  .map(arg => arg*11)
);

Object.values( )配列としてオブジェクトの値を返し、以来、argumentsオブジェクトがある、それは基本的に変換されますargumentsので、のような配列のヘルパー機能のすべてをご提供し、配列にmapforEachfilter、など


0

Benshmarck 3メソッド:

function test()
{
  console.log(arguments.length + ' Argument(s)');

  var i = 0;
  var loop = 1000000;
  var t = Date.now();
  while(i < loop)
  {
      Array.prototype.slice.call(arguments, 0); 
      i++;
  }
  console.log(Date.now() - t);


  i = 0,
  t = Date.now();
  while(i < loop)
  {
      Array.apply(null, arguments);
      i++;
  }
  console.log(Date.now() - t);

  i = 0,
  t = Date.now();
  while(i < loop)
  {
      arguments.length == 1 ? [arguments[0]] : Array.apply(null, arguments);
      i++;
  }
  console.log(Date.now() - t);
}

test();
test(42);
test(42, 44);
test(42, 44, 88, 64, 10, 64, 700, 15615156, 4654, 9);
test(42, 'truc', 44, '47', 454, 88, 64, '@ehuehe', 10, 64, 700, 15615156, 4654, 9,97,4,94,56,8,456,156,1,456,867,5,152489,74,5,48479,89,897,894,894,8989,489,489,4,489,488989,498498);

結果?

0 Argument(s)
256
329
332
1 Argument(s)
307
418
4
2 Argument(s)
375
364
367
10 Argument(s)
962
601
604
40 Argument(s)
3095
1264
1260

楽しい !


1
以下のようなものに変更することをお勧めしたいarguments.length == 1?[arguments[0]]:Array.apply(null, arguments);だけ1つの整数引数で呼び出される関数を防ぐためにdummyFn(3)、結果を引き起こし[,,]
用事

@nevermind良い仕事、私は編集します、あなたのバージョンはより良いです;)しかし、私dummyFn(3)はこれが何であるか理解できませんか?この機能は存在しません...
マトリックス

ええと...気にしないでください。例として、関数が1つの整数引数だけで呼び出され、固定サイズの空の配列がどのように呼び出されるかを示します。私の英語では申し訳ありません。
用事

0

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

document.body.innerHTML = sortArgs(1, 2, 3, 4).toString();


0

残りのパラメータはうまく機能しますがarguments、何らかの理由で引き続き使用したい場合は、

function sortArgs() {
  return [...arguments].sort()
}

[...arguments]はの一種の代替と考えることができますArray.from(arguments)。これも完全にうまく機能します。

ES7の代替案は配列内包です:

[for (i of arguments) i].sort()

これは、並べ替えの前に引数を処理またはフィルタリングする場合に最も簡単です。

[for (i of arguments) if (i % 2) Math.log(i)].sort()

0
 function x(){
   var rest = [...arguments]; console.log(rest);return     
   rest.constructor;
 };
 x(1,2,3)

簡単な破壊テクニックを試しました


0

Argumentsオブジェクトは、関数本体内でのみ使用できます。配列のようにArgumentsオブジェクトにインデックスを付けることはできますが、配列ではありません。長さ以外の配列プロパティはありません。

// function arguments length 5
function properties(a,b,c,d,e){
var function_name= arguments.callee.name
var arguments_length= arguments.length;
var properties_length=  properties.length; 
var function_from= properties.caller.name;
console.log('I am the function name: '+ function_name);
console.log('I am the function length, I am function spacific: '+ properties_length); 
console.log('I am the arguments length, I am context/excution spacific: '+ arguments_length);
console.log('I am being called From: '+  function_from );
}

// arguments 3
function parent(){
properties(1,2,3);
}

//arguments length 3 because execution spacific
parent();

この例でわかるように、配列のようにインデックスを付けることができますが、

function add(){

var sum=0;

for(var i=0; i< arguments.length;i++){

sum = sum + arguments[i];

}

return sum;

}

console.log(add(1,2,3));

ただし、Argumentsオブジェクトは配列ではなく、長さ以外のプロパティはありません。

引数オブジェクトを配列に変換できます。この時点で、引数オブジェクトにアクセスできます。

関数本体内の引数オブ​​ジェクトにアクセスする方法はたくさんありますが、これらには次のものが含まれます。

  1. Array.prototoype.slice.callメソッドを呼び出すことができます。

Array.prototype.slice.call(引数)

function giveMeArgs(arg1,arg2){

var args = Array.prototype.slice.call(arguments);
return args
}

console.log( giveMeArgs(1,2));

  1. 配列リテラルを使用できます

[] .slice.call(arguments)。

function giveMeArgs(arg1,arg2){

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

return args;

}

console.log( giveMeArgs(1,2) );

  1. あなたはレストを使用することができます...

function giveMeArgs(...args){

return args;

}

console.log(giveMeArgs(1,2))

  1. スプレッドを使用できます[...]

function giveMeArgs(){

var args = [...arguments];
return args;

}

console.log(giveMeArgs(1,2));

  1. あなたはArray.from()を使うことができます

function giveMeArgs(){

var args = Array.from(arguments);

return args;

}

console.log(giveMeArgs(1,2));


0

再利用可能な関数を作成して任意の引数で実行できます。最も単純な関数は次のようなものです。

function sortArgs() {
  return [...arguments].sort();
}

sortArgs('ali', 'reza', 1, 2, 'a'); //[1, 2, "a", "ali", "reza"];

スプレッド構文はES6以降で使用できます...

ただし、ES5以前と互換性のあるものを使用する場合は、を使用できるためArray.prototype.slice.call、コードは次のようになります。

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

sortArgs('ali', 'reza', 1, 2, 'a'); //[1, 2, "a", "ali", "reza"];

これを行う他の方法もいくつArray.fromかあります。たとえば、引数を使用またはループして、それらを新しい配列に割り当てます...


-2

これは非常に古い質問ですが、以前の解決策よりも少し入力しやすく、外部ライブラリに依存しない解決策があると思います。

function sortArguments() {
  return Array.apply(null, arguments).sort();
}

2
Array.apply正の整数の引数が1つしかない場合は機能しません。これはnew Array(3)、配列の長さがになるためです3。より具体的に言うと、結果はになる[undefined, undefined, undefined]はず[3]です。
inf3rno 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.