ChatGPT解决这个技术问题 Extra ChatGPT

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

想要改进这篇文章?提供这个问题的详细答案,包括引文和解释为什么你的答案是正确的。没有足够细节的答案可能会被编辑或删除。

JavaScript 中的 arguments 对象是一个奇怪的缺陷——它在大多数情况下就像一个数组,但它实际上不是一个数组对象。由于它是 really something else entirely,它没有 Array.prototype 中的有用功能,如 forEachsortfiltermap

使用简单的 for 循环从 arguments 对象构造一个新数组非常容易。例如,此函数对其参数进行排序:

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

然而,仅仅为了访问极其有用的 JavaScript 数组函数而不得不这样做是一件相当可怜的事情。有没有使用标准库的内置方法?


c
ctrl-alt-delor

ES6 使用剩余参数

如果你能够使用 ES6,你可以使用:

Rest Parameters

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

正如您在 link 中所读到的

剩余参数语法允许我们将不定数量的参数表示为一个数组。

如果您对 ... 语法感到好奇,它被称为 Spread Operator,您可以阅读更多信息 here

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

实际上,您可以在参数对象上使用 Arrayslice 函数,它会将其转换为标准 JavaScript 数组。您只需通过 Array 的原型手动引用它:

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

为什么这行得通?好吧,下面是 ECMAScript 5 documentation itself 的摘录:

注意: slice 函数是故意通用的;它不要求它的 this 值是一个 Array 对象。因此,它可以转移到其他类型的对象中用作方法。切片函数能否成功应用于宿主对象取决于实现。

因此,slice 适用于任何具有 length 属性的东西,而 arguments 很方便。

如果 Array.prototype.slice 对您来说太多了,您可以使用数组文字稍微缩写它:

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

但是,我倾向于觉得前一个版本更明确,所以我更喜欢它。滥用数组字面量表示法让人感觉很笨拙,看起来很奇怪。


在最近的 Firefox 版本(2.0?)和 ECMAScript 5 中,有一个 Array.slice 方法可以让这变得更简单一些。你可以这样称呼它:var arge = Array.slice(arguments, 0);。
0 有什么用?既然没有要传递的参数,为什么不能只使用 var args = Array.prototype.slice.call(arguments); ? [ MDC 参数页面 ](developer.mozilla.org/en/JavaScript/Reference/…) 建议不带 0 的方法。
@Barney - 排序是必要的,因为原始问题想要对参数进行排序。如果您只想将其转换为数组,则没有必要。
“你不应该对参数进行切片,因为它会阻止 JavaScript 引擎(例如 V8)中的优化。” - 来自 MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
我不确定这是对原始问题的回答。时间过去了。随着 ES6 在 Firefox 和 Chrome 中的试验,rest 参数 正在成为一个不错的选择 - 来自 MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…function sortArgs(...argsToSort) { return argsToSort.sort(); }
Y
Yves M.

还值得参考 this Bluebird promises library wiki page,它展示了如何将 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);。作者还展示了构建步骤如何帮助减少冗长。


+1 并感谢您提供指向 Bluebird Optimization Killer 页面的链接。 PS:我最近在 node-thunkify 项目中看到了这种优化。
对于任何在 2021 年阅读的人,在链接页面上:“请不要将这里写的任何内容作为性能建议,这是出于历史原因。”
a
animuson
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})

L
LightSpeedC Kazuaki Nishizawa

利用:

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 版本(比 slice 更慢、更快):

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

请注意,由于 Array.concat 中的扁平化行为,它将接受数组参数。 sortArguments(2,[3,0],1) 返回 0,1,2,3。
b
brad

如果您使用的是 jQuery,我认为以下内容更容易记住:

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

这基本上就是我在纯 JS 中寻找的东西,但是 +1 是 jQuery 如何使 JS 更容易理解的可靠示例。
“除非还包括框架/库的另一个标签,否则需要纯 JavaScript 答案。”
M
Michał Perłakowski

在 ECMAScript 6 中,不需要使用像 Array.prototype.slice() 这样的丑陋黑客。您可以改为使用 spread syntax (...)

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

它可能看起来很奇怪,但它相当简单。它只是提取 arguments' 元素并将它们放回数组中。如果您仍然不明白,请参阅以下示例:

控制台.log([1, ...[2, 3], 4]);控制台.log([...[1, 2, 3]]);控制台.log([...[...[...[1]]]]);

请注意,它在 IE 11 等一些较旧的浏览器中不起作用,因此如果您想支持这些浏览器,则应使用 Babel


G
Gheljenor

Here is benchmark 几种将参数转换为数组的方法。

至于我,少量论点的最佳解决方案是:

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 中的速度比 Array.apply 快 6 倍,但在最新的 Chrome 中慢两倍。
由于 Array.prototype.slice 已被弃用,因为它阻止了 JS V8 引擎优化,我认为这是最好的解决方案,直到 ES6 被广泛使用 +1
此外,Array.slice() 等数组泛型方法也已被弃用
j
jjbskir

我推荐使用 ECMAScript 6 spread operator,它将尾随参数绑定到一个数组。使用此解决方案,您无需触摸 arguments 对象,您的代码将得到简化。该解决方案的缺点是它不适用于大多数浏览器,因此您必须使用 JS 编译器,例如 Babel。在底层,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();
}

Z
Zane

罗达什:

var args = _.toArray(arguments);

在行动:

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

产生:

[2,3]

为什么不_.toArray
_.toArray 更合适。
我认为 _.slice 更合适,因为您经常想放弃一些主要论点。
M
Michał Perłakowski

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

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

请注意,它在 IE 11 等一些较旧的浏览器中不起作用,因此如果您想支持这些浏览器,则应使用 Babel


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

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


M
Mystical

这是一个干净简洁的解决方案:

函数 argsToArray() { return Object.values(arguments); } // 示例用法 console.log( argsToArray(1, 2, 3, 4, 5) .map(arg => arg*11) );

Object.values( ) 会将对象的值作为数组返回,并且由于 arguments 是一个对象,它本质上会将 arguments 转换为数组,从而为您提供数组的所有辅助函数,例如 mapforEachfilter 等。


L
LightSpeedC Kazuaki Nishizawa

另一个答案。

使用黑魔法咒语:

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

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


这绝对是最好的解决方案......如果你想让你的代码完全不可读。此外,__proto__ 已被弃用。请参阅MDN docs
g
guest271314

尝试使用 Object.setPrototypeOf()

说明:将 argumentsprototype 设置为 Array.prototype

函数 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 循环

函数 toArray() { 让 arr = []; for (let prop of arguments) arr.push(prop);返回 arr } console.log(toArray("abc", 123, {def:456}, [0,[7,[14]]]))

Object.create()

说明:创建对象,将对象的属性设置为arguments的每个索引处的项目;将创建的对象的 prototype 设置为 Array.prototype

函数 toArray() { var obj = {}; for (var prop in arguments) { obj[prop] = { value: arguments[prop], writable: true, enumerable: true, 可配置: true } } return Object.create(Array.prototype, obj); } console.log(toArray("abc", 123, {def: 456}, [0, [7, [14]]]))


您一直asking people您的答案是否满足“长答案”问题下的警告。在我看来,您回答的主要问题是您没有解释为什么应该使用您在此处显示的任何方法。我不可能使用您提出的任何解决方案,因为它们都比公认答案中的解决方案更糟糕。例如,您对 Object.setPrototypeOf 的文档的引用警告说这是一个“非常慢的操作”。我到底为什么要在 Array.prototype.slice.call 上使用它?
@Louis 更新了答案,并对每种方法进行了解释。 OP 的问题似乎是“是否有使用标准库的内置方法?” ,而不是内置的“为什么要使用任何方法”?发布答案的任何用户如何准确确定发布的解决方案对于 OP 是否“正确”?似乎这取决于 OP 来确定?实际上,这部分通知是这个用户感兴趣的:“解释为什么你的答案是正确的”。提供给这个问题的任何答案是否表明:“这个答案是“正确的”,因为:x、y、z”?
我解释的是 SO 通常是如何工作的。 OP 是否想知道为什么一种解决方案比另一种更好是完全不相关的,因为为 SO 发布的问题主要不是针对 OP,而是针对稍后将阅读问题及其答案的成千上万的人。此外,对答案进行投票的人不需要根据 OP 可能满意的任何内容进行投票。
M
Matrix

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

享受 !


建议修改为 arguments.length == 1?[arguments[0]]:Array.apply(null, arguments); 之类的内容,以防止仅使用一个整数参数 dummyFn(3) 调用该函数并导致结果 [,,]
@nevermind 干得好,我编辑,你的版本更好;)但我不明白dummyFn(3)这是什么?这个功能不存在...
呃......没关系,只是一个例子想展示一个函数如何只用一个整数参数调用并导致一个固定大小的空数组,对不起我的英语。
w
wsc

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 的替代方案是数组推导:

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

如果您想在排序之前处理或过滤参数,这可能是最简单的:

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

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

我尝试了简单的破坏技术


R
Rick

Arguments 对象仅在函数体内可用。尽管您可以像数组一样索引 Arguments 对象,但它不是数组。除了长度之外,它没有任何数组属性。

// 函数参数长度 5 函数属性(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('我是函数名:'+ function_name); console.log('我是函数长度,我是函数空间:'+ properties_length); console.log('我是参数长度,我是上下文/执行空间:'+ arguments_length); console.log('我被称为 From: '+ function_from ); } // 参数 3 function parent(){ properties(1,2,3); } //参数长度为 3 因为执行空间 parent();

虽然它可以像数组一样被索引,如您在此示例中所见:

函数 add(){ var sum=0; for(var i=0; i< arguments.length;i++){ sum = sum + arguments[i]; } 返回总和; } 控制台日志(添加(1,2,3));

但是,Arguments 对象不是一个数组,并且除了长度之外没有任何其他属性。

您可以将 arguments 对象转换为数组,此时您可以访问 Arguments 对象。

您可以通过多种方式访问函数体内的参数对象,其中包括:

你可以调用 Array.prototoype.slice.call 方法。

Array.prototype.slice.call(参数)

函数 giveMeArgs(arg1,arg2){ var args = Array.prototype.slice.call(arguments); return args } console.log( giveMeArgs(1,2));

您可以使用数组文字

[].slice.call(参数)。

函数 giveMeArgs(arg1,arg2){ var args = [].slice.call(arguments);返回参数; } console.log(给MeArgs(1,2));

你可以使用休息...

函数 giveMeArgs(...args){ 返回参数; } console.log(giveMeArgs(1,2))

您可以使用传播 [...]

函数 giveMeArgs(){ var args = [...arguments];返回参数; } console.log(giveMeArgs(1,2));

你可以使用 Array.from()

函数 giveMeArgs(){ var args = Array.from(arguments);返回参数; } console.log(giveMeArgs(1,2));


A
Alireza

您可以创建一个可重用的函数来使用任何参数,最简单的是这样的:

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 或循环遍历 arguments 并将它们分配给新数组...


H
HandyAndyShortStack

这是一个非常古老的问题,但我认为我有一个解决方案,它比以前的解决方案更容易输入,并且不依赖于外部库:

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

如果您只有一个正整数参数,Array.apply 将不起作用。这是因为 new Array(3) 创建了一个长度为 3 的数组。更具体地说,结果将是 [undefined, undefined, undefined] 而不是 [3]