更简洁的处理Array.prototype.slice.call(arguments)方法

4
我正在编写几个函数,它们需要不同类型的参数。因此,最简单的方法就是这样做:

var myFunc = function() {
    var args = Array.prototype.slice.call(arguments)
}

与其直接在函数声明的参数字段中处理所有不同的可能性,不如使用更简单的方法:

var myFunc = function(param1, param2, param3) {
    if (param3) {
        // etc.
    }
}

Array.prototype.slice.call(arguments)虽然很有用,但会降低代码的可读性。我正在尝试找出一种编写帮助程序的方式,它可以完成与Array.prototype.slice.call()相同的任务,但更加简洁和易读。我正在试着这样做:

var parseArgs = function() {
    return Array.prototype.slice.call(arguments)
}

var foo = function() {
    console.log(parseArgs(arguments))
}

foo('one', 'two', 'three')
// [Arguments, ['one', 'two', 'three']]

但显然,这并不起作用。

不确定您的确切用例,但也许选项对象模式是更好的选择,例如:function foo(o) { log(o.name) } foo({ name: "Bar" }) - lleaff
@lleaff,不幸的是,这需要比那更灵活。 - brandonscript
5个回答

5
如果你不想每次都写 Array.prototype.slice.call(args),可以这样做:
var slice = Function.call.bind(Array.prototype.slice);

然后你就可以在任何地方使用它,例如:

function fn(){
    var arr = slice(arguments);
}

我正在使用Node.js,所以虽然这个方法可以在一个脚本中运行,但是我不认为它可以在module.exports()中起作用。 - brandonscript
它也应该在Node上运行。除非你对它们的全局变量做了一些奇怪的事情。 - MinusFour
我猜这取决于我加载实现该模块的位置。如果我在加载任何其他依赖于它的模块之前这样做,那么它可能会起作用。 - brandonscript
@remus 这个也可以工作,因为它不使用任何特定于浏览器/节点的功能 :-) - thefourtheye
哦,是的,我意识到它不是特定于Node的。 - brandonscript

3

以下是将类数组对象转换为实际数组的几个JS简写:

别名 Array.prototype.slice

(function (slice) {
  ...your code...
  function someFunction() {
    var args = slice.call(arguments);
    ...
  }
  ...
}(Array.prototype.slice));

使用 [].slice

function someFunction() {
  var args = [].slice.call(arguments);
}

创建自己的切片(你尝试过,但参数出错了):
function slice(arr) {
  return Array.prototype.slice.call(arr);
}
function someFunction() {
  var args = slice(arguments);
}

使用现代的 Array.from(请确保进行向后兼容性的polyfill):

function someFunction() {
  var args = Array.from(arguments);
}

如果你在一个可以安全使用展开操作符的环境中,那么就不需要调用slice方法:

function someFunction() {
  var args = [...arguments];
}

或者,var args = [...arguments];. - user663031

2

您需要传递 foo 函数的参数对象,并仅对其进行切片,如下所示:

function parseArgs(args) {
    return Array.prototype.slice.call(args);
}

当你在parseArgs函数内使用arguments时,它只会引用该函数接收到的参数,而不是foo函数接收到的参数。


在ECMA Script 2015中,你可以直接在arguments对象上使用Array.from,像这样:

function foo() {
    console.log(Array.from(arguments));
}

或者,你可以保持parseArgs不变,在ECMA Script 2015中将arguments展开到parseArgs上,像这样:

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

function foo() {
    console.log(parseArgs(...arguments));
}

这基本上意味着你正在展开由 foo 收到的 arguments ,并将它们传递给 parseArgs ,以便它也可以接收相同的参数。

1
什么情况?
var parseArgs = function(args) {
    return Array.prototype.slice.call(args)
}

var foo = function() {
    console.log(parseArgs(arguments))
}

foo('one', 'two', 'three')

这样你就可以解析实际的参数数组。

或者,您可以将“slice”缓存起来,以避免在每次调用时进行间接引用的性能损失:var slice = Array.prototype.slice;。或者直接绑定所有内容:var parseArgs = Function.call.bind(Array.prototype.slice) - oligofren

1

有很多使用arguments的方式会导致函数无法被优化。在使用arguments时必须非常小心。

来自于MDN上的 arguments 对象:

重要提示:不应该对 arguments 进行切片,因为它会阻止 JavaScript 引擎(例如 V8)进行优化。相反,尝试通过遍历 arguments 对象来构造一个新数组。

由于 Node.js 使用 V8 引擎,您可能想这样做:

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

function myFunc() {
  var args = parseArgs.apply(null, arguments);
  console.log(args); // => [1,2,3]
}

myFunc(1, 2, 3);


是的,我了解所有这些 - 这就是为什么我正在使用MDN推荐的Array.prototype.slice.call()方法。 - brandonscript
2
@remus,MDN建议不要使用Array.prototype.slice.call进行性能优化。当然,Array.prototype.slice.call(arguments)很少会成为瓶颈,所以我不会太担心这个特定问题。 - zzzzBov
有趣的是,MDN的警告有点模糊不清;它听起来更像是在说你不应该直接使用arguments.slice()。我想我误解了它。 - brandonscript
@brandonscript,没有arguments.slice,所以你不能直接调用它。slice是一个数组方法,而arguments不是,这也是你首先将arguments转换为数组的原因。所以这一点并不含糊。只需在控制台中尝试此操作即可:(function (){ return arguments.slice(); })(1,2,3) - oligofren

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接