如何将“参数”对象转换为JavaScript中的数组?

在JavaScript中的arguments对象是一个奇怪的疣 – 它在大多数情况下就像一个数组,但它实际上不是一个数组对象。 由于它完全是其他的东西 ,它没有Array.prototype的有用函数,比如forEachsortfiltermap

用一个简单的for循环来从一个参数对象构造一个新的数组是非常容易的。 例如,这个函数对它的参数进行sorting:

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

然而,这仅仅是为了访问非常有用的JavaScript数组函数而必须做的一件相当可怜的事情。 有使用标准库的内置方法吗?

实际上,你可以在一个arguments对象上使用Arrayslice函数,然后将它转换成一个标准的JavaScript数组。 你只需要通过Array的原型手动引用它:

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

为什么这个工作? 那么,下面是ECMAScript 5文档本身的摘录:

注意slicefunction是有意通用的; 它不要求它的这个值是一个Array对象。 因此可以将其转换为其他types的对象用作方法。 slice函数是否可以成功应用于主机对象取决于实现。

因此, slice对具有length属性的任何东西都适用,这些arguments方便地进行。


如果Array.prototype.slice对你来说太过分了,可以使用数组文字略微缩写一下:

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

不过,我倾向于认为前一个版本更加明确,所以我更喜欢它。 滥用数组文字符号感觉很乱,看起来很奇怪。

如果您可以使用ES6,则可以使用:

其余参数

 function sortArgs(...args) { return args.sort(function (a, b) { return a - b; }); } document.body.innerHTML = sortArgs(12, 4, 6, 8).toString(); 

还有一点值得引用这个Bluebird Promises库wiki页面 ,它展示了如何在V8 JavaScript引擎下以V8 JavaScript引擎的优化方式pipe理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); 。 作者还展示了构build步骤如何帮助减less冗长。

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

使用:

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

如果您使用的是jQuery,那么在我看来,以下是更容易记住的事情:

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

这里是将参数转换为数组的几种方法的基准 。

对我而言,less量参数的最佳解决scheme是:

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

我build议使用ECMAScript 6 扩展运算符 ,它将绑定尾部参数到一个数组。 有了这个解决scheme,你不需要触及arguments对象,你的代码将被简化。 这个解决scheme的缺点是它不能在大多数浏览器上运行,所以你需要使用一个JS编译器,例如Babel。 Babel将arguments转换为带有for循环的数组。

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

如果您不能使用ECMAScript 6,我build议您查看一些其他答案,如@Jonathan Fingland

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

使用Array.from() ,它将类似数组的对象(如arguments )作为参数,并将其转换为数组:

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

在ECMAScript 6中,不需要像Array.prototype.slice()那样使用丑陋的黑客。 你可以使用扩展语法( ...

 (function() { console.log([...arguments]); }(1, 2, 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)); 

Lodash:

 var args = _.toArray(arguments); 

在行动:

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

生产:

 [2,3] 

另一个答案。

使用黑魔法:

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

Firefox,Chrome,Node.js,IE11都可以。

尝试使用Object.setPrototypeOf()

说明:将arguments prototype设置为Array.prototype

 function toArray() { return Object.setPrototypeOf(arguments, Array.prototype) } console.log(toArray("abc", 123, {def:456}, [0,[7,[14]]])) 

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 

请享用 !

 function sortArgs(...args) { return args.sort(function (a, b) { return a - b; }); } document.body.innerHTML = sortArgs(1, 2, 3, 4).toString(); 

虽然其他参数运行良好,但如果因为某些原因想继续使用arguments ,请考虑

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

[...arguments]可以被认为是Array.from(arguments)的一种替代方法,这也可以很好地工作。

一个ES7的select是一个数组理解:

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

如果要在sorting之前处理或过滤参数,这可能是最简单的:

 [for (i of arguments) if (i % 2) Math.log(i)].sort() 
  function x(){ var rest = [...arguments]; console.log(rest);return rest.constructor; }; x(1,2,3) 

我尝试了简单的破坏技术

参数对象只在函数体内可用。 虽然你可以像数组一样索引参数对象,但它不是一个数组。 它没有长度以外的任何数组属性。

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

这是一个非常古老的问题,但是我认为我有一个比以前的解决scheme稍微容易一些的解决scheme,并且不依赖于外部库:

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