【问题标题】:Why doesn't ["A","B","C"].map(String.prototype.toLowerCase.call) work?为什么 ["A","B","C"].map(String.prototype.toLowerCase.call) 不起作用?
【发布时间】:2014-04-24 22:25:22
【问题描述】:

当然,这会返回您所期望的:

["A","B","C"].map(function (x) {
    return x.toLowerCase();
});
// --> ["a", "b", "c"]

使用 String.prototype.toLowerCase.call 也是如此:

["A","B","C"].map(function (x) {
    return String.prototype.toLowerCase.call(x);
});
// --> ["a", "b", "c"]

如果你传递 map 给出的额外参数,它也可以工作,因为它会丢弃参数:

["A","B","C"].map(function (x, index, arr) {
    return String.prototype.toLowerCase.call(x, index, arr);
});
// --> ["a", "b", "c"]

但是,这不起作用:

["A","B","C"].map(String.prototype.toLowerCase.call);
// --> TypeError: undefined is not a function

以下也不起作用,因为arguments 具有 Object 原型而不是 Array 原型,因此 slice 未定义。上述行为的原因可能是因为这样的原因——在内部使用了 slice 或其他类似的 Array 函数?

["A","B","C"].map(function (x) {
    return String.prototype.toLowerCase.apply(x, arguments.slice(1));
});
// --> TypeError: undefined is not a function

【问题讨论】:

  • 您将call 函数传递给map,它与['A','B','C'].map(Function.prototype.call) 相同,您希望以在每个元素上调用String.prototype.toLowerCase 函数的方式传递数组。
  • 执行此操作的正确方法是代码中的第一个示例。

标签: javascript


【解决方案1】:

类似问题:Why won't passing `''.trim()` straight to `[].map()`'s callback work?

Map 有一个可选的 thisArg,可以像这样使用:

['A', 'B', 'C'].map(Function.prototype.call, String.prototype.toLowerCase);  
// gives ["a", "b", "c"]

【讨论】:

    【解决方案2】:

    这是 JavaScript 点符号的一种特殊行为。

    toLowerCase.call(x) 正在工作,因为 JavaScript 在执行 call 时使用 toLowerCase 作为 this。这就是 call(与您在每个函数中找到的 Function.prototype.call 相同)知道您希望它执行 toLowerCase 的方式。

    call 传递给另一个函数会丢失该引用,因此this 不再引用toLowerCase

    【讨论】:

    • JavaScript 引擎执行call 并在call 内执行this 值,在正确的代码中恰好是toLowerCase。你说的和我说的都是事实。
    • 这并不能真正解释这种行为!技巧问题,为什么[1,2,3].map(Math.sqrt) 有效,而["A","B","C"].map(String.toLowerCase) 无效?
    • Math.sqrt 可以安全地与Math 分开,因为本质上是一个实现细节,您需要记住它才能被信任。 Math.sqrt 不使用它的 this 值,通常只是 Math
    • 啊,我明白了!我没有想到 Javascript 中只有一个 call(),它使用 this 来获取前面的函数,就像其他语言一样。
    • @Cory - 现在你正在做一些事情,String 的方法是如何工作的,这使得它们不适合直接传递给像 map() 这样的方法,以及为什么 OP 的问题中的第一个示例一般应该用,为什么Math的方法可以安全通过
    【解决方案3】:

    问题在于String.prototype.toLowerCase.call == Function.prototype.call。如果你想获得一个将参数转换为小写的函数,你可以像这样将toLowerCase 函数绑定到call 函数:

    var toLowerCase = String.prototype.toLowerCase.call.bind(String.prototype.toLowerCase);
    ["A","B","C"].map(toLowerCase);
    

    【讨论】:

      【解决方案4】:

      但是,这不起作用:

      ["A","B","C"].map(String.prototype.toLowerCase.call);

      传递给map 的第一个参数应该是一个函数,它将传递数组成员的值。上面传递了一个对Function.prototype.call的直接引用,所以函数会尝试:

      call(x);
      

      所以call已经通过了,没有设置它的this,所以进入call函数就会undefined

      【讨论】:

        猜你喜欢
        • 2014-10-08
        • 2019-10-27
        • 2010-11-04
        • 1970-01-01
        • 2011-05-30
        • 2018-08-11
        • 2014-03-29
        • 2021-10-06
        • 1970-01-01
        相关资源
        最近更新 更多