【问题标题】:NodeJS: Functional Programming - No access to prototype in handover functionNodeJS:函数式编程 - 在切换功能中无法访问原型
【发布时间】:2017-07-10 01:11:21
【问题描述】:

我尝试编写一个函数,该函数返回某个 API (AgileCRMManager) 的承诺版本。 api 的设计与 request 非常相似。

但是我在功能的移交方面遇到了一些问题。该函数无法访问它自己的原型。我得到以下日志输出:

[Function: getContactByEmail]
[Function: getContactByEmail]
TypeError: this.getOptions is not a function
    at getContactByEmail (/Users/Tilman/Documents/Programme/NodeJS/async_test/node_modules/agile_crm/agilecrm.js:116:24)
    at /Users/Tilman/Documents/Programme/NodeJS/async_test/routes/portal.js:30:5
    at restPromise (/Users/Tilman/Documents/Programme/NodeJS/async_test/routes/portal.js:29:10)
    at Object.<anonymous> (/Users/Tilman/Documents/Programme/NodeJS/async_test/routes/portal.js:22:1)
    at Module._compile (module.js:541:32)
    at Object.Module._extensions..js (module.js:550:10)
    at Module.load (module.js:456:32)
    at tryModuleLoad (module.js:415:12)
    at Function.Module._load (module.js:407:3)
    at Function.Module.runMain (module.js:575:10)

这是来自agile_crm 的getOptions 部分:

ContactAPI.prototype.getOptions = function getOptions() {
    this._options = {
        host: this.domain,
        headers: {
            'Authorization': 'Basic ' + new Buffer(this.email + ':' + this.key).toString('base64'),
            'Accept': 'application/json'
        }
    };

    return this._options;
};

这是我的代码(如果我用 a.contactAPI.getContactByEmail 更改 restFunction,它可以工作。但我想拥有更多功能):

var AgileCRMManager = require("agile_crm")
var a = new AgileCRMManager("user-domain",
        "api-key",
        "user-mail")

restPromise('ds@umzuege-selisch.de',a.contactAPI.getContactByEmail)
  .then(console.log)
  .catch(console.error)

function restPromise(data, restFunction) {
  console.log(restFunction);                    // => [Function: getContactByEmail]
  console.log(a.contactAPI.getContactByEmail);  // => [Function: getContactByEmail]
  return new Promise(function(fulfill, reject){
    //a.contactAPI.getContactByEmail(
    restFunction(
      data,
      function(data){
        fulfill(data)
      },
      function(error){
        reject(new Error(error))
      }
    )
  })
}

任何想法我可以如何交出功能和 api 仍然可以工作?

【问题讨论】:

  • 我看不到您调用 getOptions 的任何地方。由于this 的值取决于你如何调用函数(而不是你如何定义它),如果你不展示你如何调用 getOptions,我们将无法帮助你
  • 我没有在我的代码中调用 getOptions。我使用的库agile_crm 提供的函数调用getOptions。带有函数 getOptions 的代码来自我在代码中需要的 node_modules/agile_crm 下的文件。
  • 好的。我明白发生了什么。

标签: javascript node.js promise


【解决方案1】:

您误解了 this 在 javascript 中的工作原理。通常我会投票结束这样的问题,但这似乎是一个需要进一步解释的特定用例。有关this 工作原理的完整说明,我建议阅读以下问题的答案:How does the "this" keyword in Javascript act within an object literal?

理论

现在,问题是在 js 中 this 的值取决于你如何调用函数。如果函数是方法,this 会解析为该方法所属的对象:

a.foo = function () { console.log(this) };
a.foo() // should output `a`

但是如果函数是一个不属于对象的简单函数,那么this 要么是全局对象(浏览器中的窗口),要么是未定义的,具体取决于严格模式。请注意,js解释天气与否,函数是调用函数时的方法。不是在定义函数时。这会产生有趣的后果:

a.foo = function () { console.log(this) };
b = a.foo;
b(); // here b is a simple function because it's not something.b
     // so the output is either the global object or undefined

虫子

这就是这行代码发生的事情:

restPromise('ds@umzuege-selisch.de',a.contactAPI.getContactByEmail)

您将 a.contactAPI.getContactByEmail 作为函数引用传递。因此它失去了它是a.contactAPI 的一部分这一事实,而是变成了一个简单的函数。通过调用函数的方式可以清楚地看出这一事实:

restFunction( //...

请注意,您调用的是restFunction,它是对a.contactAPI.getContactByEmail 的函数引用。由于它被简单地称为restFunction() 而不是a.contactAPI.restFunction(),因此函数中的this 指向全局对象(或未定义,取决于严格模式)而不是a.contactAPI

修复

有几种方法可以解决此问题。

  1. a.contactAPI.getContactByEmail 包装在一个匿名函数中,以便您可以使用正确的this 调用它:

    restPromise(
      'ds@umzuege-selisch.de',
      function(data,ok,err){
        a.contactAPI.getContactByEmail(data,ok,err);
      }
    )
    
  2. 使用.bind():

    restPromise(
      'ds@umzuege-selisch.de',
      a.contactAPI.getContactByEmail.bind(a.contactAPI)
    )
    
  3. 修改 restPromise() 以接受对象而不是函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-29
    • 1970-01-01
    • 2017-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多