如何将“参数”对象转换为JavaScript中的数组?
在JavaScript中的arguments
对象是一个奇怪的疣 – 它在大多数情况下就像一个数组,但它实际上不是一个数组对象。 由于它完全是其他的东西 ,它没有Array.prototype
的有用函数,比如forEach
, sort
, filter
和map
。
用一个简单的for循环来从一个参数对象构造一个新的数组是非常容易的。 例如,这个函数对它的参数进行sorting:
function sortArgs() { var args = []; for (var i = 0; i < arguments.length; i++) args[i] = arguments[i]; return args.sort(); }
然而,这仅仅是为了访问非常有用的JavaScript数组函数而必须做的一件相当可怜的事情。 有使用标准库的内置方法吗?
实际上,你可以在一个arguments对象上使用Array
的slice
函数,然后将它转换成一个标准的JavaScript数组。 你只需要通过Array的原型手动引用它:
function sortArgs() { var args = Array.prototype.slice.call(arguments); return args.sort(); }
为什么这个工作? 那么,下面是ECMAScript 5文档本身的摘录:
注意 :
slice
function是有意通用的; 它不要求它的这个值是一个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(); }