【问题标题】:Utterly bewildered by JS 'arguments' peculiarity [duplicate]对 JS 的“论点”特性感到非常困惑 [重复]
【发布时间】:2015-11-14 20:19:45
【问题描述】:

我有这个电话:

function del(Model, modelName, model_id, req, res, next, cb) {

    if(req.query.optimisticDelete){
        optimisticDelete(arguments);
    }
    else{
        pessimisticDelete(arguments);
    }
}

问题当然是参数没有正确传递给optimisticDelete 和pessimisticDelete 函数。

在理想的 JS 世界中,这可能会起作用,但我很容易看出为什么它不起作用。

但这并不能消除我只是不想为每次调用输入所有参数的事实,事实上我也想省略 del 函数签名中的参数,所以这将是最理想的情况,虽然我需要对 req 对象的引用,但我现在缺少它:

  function del() {

        if(req.query.optimisticDelete){
            optimisticDelete(arguments);
        }
        else{
            pessimisticDelete(arguments);
        }
    }

当然,当参数被传递时,它似乎并没有神奇地分成单独的参数。

而且,这也不起作用:

function del(Model, modelName, model_id, req, res, next, cb) {

    if(req.query.optimisticDelete){
        optimisticDelete(Array.prototype.slice.call(arguments));
    }
    else{
        pessimisticDelete(Array.prototype.slice.call(arguments));
    }
}

如果你明白我想要做什么,请告诉我是否可能以及如何做,

【问题讨论】:

  • optimisticDelete.apply(null, Array.prototype.slice.call(arguments));
  • @BenTaber 在与apply 一起使用之前,您无需将arguments 转换为数组。
  • 阅读arguments 是什么将是这个问题developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 的一个很好的开始,然后搜索以前的问题将是最好的后续。

标签: javascript


【解决方案1】:

您正在使用 单个 参数调用 optimisticDelete,这是一个包含原始调用的所有参数的 arguments 特殊对象。如果你想把它们散开,你需要使用 apply:

optimisticDelete.apply(null, arguments);

不必先将arguments 转换为数组。 MDN 说:

您也可以将arguments 用于argsArray 参数。 arguments 是函数的局部变量。它可用于被调用对象的所有未指定参数。因此,当您使用apply 方法时,您不必知道被调用对象的参数。您可以使用arguments 将所有参数传递给被调用对象。

【讨论】:

  • 根据 ECMAScript 2015,Function.prototype.apply 会将 arguments 转换为 List,这似乎是比 Array 简单得多的结构。因此,按原样传递 arguments 的一个很好的理由是不要浪费时间将其转换为无论如何都会转换为 List 的 Array。 ;-)
【解决方案2】:

有两个问题。首先,arguments 对象很奇怪,但 并不奇怪。在一个简单的函数调用中,没有什么能神奇地变成参数列表。但是,Function.prototype.apply 是您最终想要的。

首先,您需要将 arguments 转换为普通数组:

var plainArgs = Array.prototype.slice.call(arguments);

或者,如果您关心运行时效率:

var plainArgs = [];
for (var i = 0; i < arguments.length; ++i)
  plainArgs[i] = arguments[i];

注意——这一步可能不是必需的,但是将arguments 对象从函数中传递出去往往会使优化器放弃他们的小手并放弃你的函数。)

另一条注释——完全忽略这些关于将arguments 传递给.apply() 的东西是不好的。我错了。)

除此之外,您可以使用.apply()

    optimisticDelete.apply(null, plainArgs);

.apply() 函数期望它的第二个参数是一个数组。该数组成为函数的各个参数。 .apply() 的第一个参数是您希望 this 在函数调用中采用的值;因为你在原始代码中调用optimisticDelete()“naked”,所以我传递了null,但你可以传递任何你想要的。

【讨论】:

  • 您不必先将其转换为数组。
  • 虽然apply() 的语法与call() 的语法几乎相同,但根本区别在于call() 接受参数列表,而apply() 接受单个参数数组。
  • @Sphvn 问题在于arguments 对象的语义很奇怪,因为arguments 的索引元素是函数实际参数的别名,因此它使静态分析变得亲切-不可能的。如果你将arguments 传递给另一个函数,V8 根本不会尝试优化你的函数。我怀疑其他优化器出于同样的原因也有同样的行为。
  • @Pointy,github.com/petkaantonov/bluebird/wiki/… 文章中的有趣点,具体来说,Never use arguments directly without .length or [i] (STRICTLY x.apply(y, arguments) is ok, nothing else is , e.g. .slice. Function#apply is special) 这是否意味着在 Barmars 答案中使用 apply 不会损害优化?
猜你喜欢
  • 1970-01-01
  • 2020-08-21
  • 2015-02-11
  • 1970-01-01
  • 1970-01-01
  • 2022-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多