【问题标题】:why `lodash.map(['A'], String.prototype.toLowerCase.call)` does not work?为什么`lodash.map(['A'], String.prototype.toLowerCase.call)` 不起作用?
【发布时间】:2014-10-08 17:38:36
【问题描述】:

如果我想将一个字符串数组转换为小写,这似乎是正常的做法:

lodash = require('lodash')
lodash.map(['A', 'B'], String.prototype.toLowerCase.call)

TypeError: object is not a function
    at Function.map (/Users/alejandro.carrasco/repos/cap-proxy/node_modules/lodash/dist/lodash.js:3508:27)
    at repl:1:9
    at REPLServer.self.eval (repl.js:110:21)
    at Interface.<anonymous> (repl.js:239:12)
    at Interface.EventEmitter.emit (events.js:95:17)
    at Interface._onLine (readline.js:202:10)
    at Interface._line (readline.js:531:8)
    at Interface._ttyWrite (readline.js:760:14)
    at ReadStream.onkeypress (readline.js:99:10)
    at ReadStream.EventEmitter.emit (events.js:98:17)

我在代码中挖了一点,似乎问题是由createCallback 包装了map 内部使用的传递函数产生的:

lodash.createCallback(String.prototype.toLowerCase.call)('A')

TypeError: object is not a function
    at repl:1:58
    at REPLServer.self.eval (repl.js:110:21)
    at Interface.<anonymous> (repl.js:239:12)
    at Interface.EventEmitter.emit (events.js:95:17)
    at Interface._onLine (readline.js:202:10)
    at Interface._line (readline.js:531:8)
    at Interface._ttyWrite (readline.js:760:14)
    at ReadStream.onkeypress (readline.js:99:10)
    at ReadStream.EventEmitter.emit (events.js:98:17)
    at emitKey (readline.js:1095:12)

但我真的不明白那里发生了什么......

我知道如果我传递这样的回调它会起作用:

function(x) {return x.toLowerCase()}

但好奇心正在杀死我......

【问题讨论】:

    标签: javascript node.js map callback lodash


    【解决方案1】:

    为什么

    ['A', 'B'].map(String.prototype.toLowerCase.call) 不起作用的相同原因 - 它有效地将 Function.prototype.call.call(thisArg, currentValue) 用作抛出 TypeError: object is not a function 的迭代器,因为您的 thisArg 是全局上下文 (process) 而不是 String.prototype.toLowerCase

    如何

    // You expect this to be your iterator:
    String.prototype.toLowerCase.call('A');
    
    // Instead, you got this:
    String.prototype.toLowerCase.call.call(thisArg, 'A');
    

    由于在您的示例中thisArg 绑定到process,因此上面的行与以下代码几乎相同: process()this 绑定到 'A'

    // The "correct" invocation "should" be:
    String.prototype.toLowerCase.call.call(String.prototype.toLowerCase, 'A');
    

    修复

    您可以通过传递“正确”thisArg 来修复它。以下是可行的,但这样的maps 在我看来并不比function(x) {return x.toLowerCase()} 好:

    ['A'].map(String.prototype.toLowerCase.call, String.prototype.toLowerCase);
    ['A'].map(String.prototype.toLowerCase.call.bind(String.prototype.toLowerCase));
    ['A'].map(Function.prototype.call, String.prototype.toLowerCase);
    ['A'].map(Function.prototype.call.bind(String.prototype.toLowerCase));
    

    upd 由于 ES2015 和 transpilers 现在已经相当成熟,我更喜欢以下:

    ['A'].map(letter => letter.toLowerCase());
    

    【讨论】:

    • 很好看!因为 call.call 引用相同的函数而不是 second degree unbounded 函数是我错过的 :)
    【解决方案2】:

    当您将String.prototype.toLowerCase.call 作为迭代器函数传递时,您实际上只是传递了call 函数,没有上下文。

    call 函数的上下文通常是应该调用的函数。在这种情况下,似乎上下文设置为某个对象(全局对象?),因此您会收到错误 object is not a function

    一种可能的解决方案是将Function.call 的上下文绑定到String.prototype.toLowerCase,如下所示:

    _.map(['A', 'B'], Function.call.bind(String.prototype.toLowerCase));
    

    或者更短一点:

    _.map(['A', 'B'], Function.call.bind("".toLowerCase));
    

    经过更多测试后,我发现以下代码适用于下划线,但不适用于 Lo-Dash,至少在浏览器中是这样:

    _.map(['A', 'B'], Function.call, "".toLowerCase);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-21
      相关资源
      最近更新 更多