【问题标题】:Class-wide object instantiated from constructor从构造函数实例化的类范围对象
【发布时间】:2014-11-28 01:47:32
【问题描述】:

使用下面的 someAPI,它需要我想在构造函数中动态分配的凭据。然后我想在整个课程中使用 someAPI。 IE。在下面的示例中,someMethodUsingSomeAPI 是我想从 B 实例中的其他方法调用的辅助方法。Coffee-/JavaScript 可以做到这一点吗? (我可以让它工作的唯一方法是将 someMethodUsingSomeAPI 放在构造函数中。)

SomeAPI = Npm.require 'someAPI'

class B extends A
  constructor: (options = {}) ->
    unless @ instanceof B
      return new B(options)

    @config = JSON.parse(Assets.getText('config/' + options.username + '.json'))

    @someAPI = new SomeAPI
      consumer_key: @config.credentials.consumer.key
      consumer_secret: @config.credentials.consumer.secret
      access_token: @config.credentials.access.token
      access_token_secret: @config.credentials.access.secret

  someMethodUsingSomeAPI = Async.wrap((id, callback) ->
    return @someAPI.get 'whatever/show', { 'id': id }, callback
  )

  console.log someMethodUsingSomeAPI '123' # Error: Cannot call method 'get' of undefined

根据 saimeunt 的建议进行了更新

...

someMethodUsingSomeAPI = (id) ->
  wrappedGet = Async.wrap(@someAPI, 'get')
  wrappedGet 'whatever/show', { id: id }

console.log someMethodUsingSomeAPI '123' # ReferenceError: someMethodUsingSomeAPI is not defined

&

b = B('username')
b.someMethodUsingSomeAPI '123' # Works!

someMethodUsingSomeAPI: 更改为someMethodUsingSomeAPI =

console.log someMethodUsingSomeAPI '123' # Error: unsupported argument list

&

b = B('username')
b.someMethodUsingSomeAPI '123' # TypeError: Object #<B> has no method 'someMethodUsingSomeAPI'

(这是 Meteor 0.9.3.1)

更新试图澄清

Here's a simplified version of the above, without any of the API stuff.

someMethod = works, someMethod: doesn't work

我很高兴classInstance.someMethod 在使用 : 时可以正常工作,但我真的很想让它在实际实例中工作。

【问题讨论】:

  • 为什么要将someAPI 设为类外部的静态变量,而不是实例property
  • 请注意,JSON.parse 确实采用 JSON 字符串,而不是文件路径。
  • 是的,很抱歉。为简洁起见,只是删除了一些。加回来了。
  • 您使用someMethodUsingSomeAPI = 应该是someMethodUsingSomeAPI:。然后,实例化 B,并在其上调用方法。或者你为什么要定义一个类?
  • 如果我将它从 = 更改为 :,我会得到 ReferenceError: someMethodUsingSomeAPI is not defined 和上面的跟踪。如果我这样做B.someMethodUsingSomeAPI '123',我会得到Cannot call method 'get' of undefined。我想从 B 中的其他方法调用这个辅助方法。

标签: javascript oop design-patterns meteor coffeescript


【解决方案1】:

当然,您可以将someAPI 附加到您的类对象上。在 coffeescript 中,@ 用于代替 this(就像在 Javscript 中一样)。

SomeAPI = require 'someAPI'

class A extends B
  constructor: (options = {}) ->
    unless @ instanceof A
      return new A(options)

    @config = JSON.parse('config/' + options.username + '.json')

    @someAPI = new SomeAPI
      consumer_key: @config.credentials.consumer.key
      consumer_secret: @config.credentials.consumer.secret
      access_token: @config.credentials.access.token
      access_token_secret: @config.credentials.access.secret

  someMethodUsingSomeAPI:  (id, callback) ->
    return @someAPI.get 'whatever/show', { 'id': id }, callback

您可以查看 this SO question,它解释了 Javascript this 及其范围。一旦你明白了,看看coffeescript's classes是如何工作的,你应该对@的使用有一定的了解。

【讨论】:

  • 谢谢。我想我首先尝试过,然后尝试在构造函数之外声明 someAPI 等。更新了原始帖子以反映我在做什么,但我仍然得到同样的错误,即Cannot call method 'get' of undefined
【解决方案2】:

我想这就是你想要的:

someMethodUsingSomeAPI:function(id){
  var wrappedGet=Async.wrap(@someAPI,"get");
  return wrappedGet("whatever/show",{
    id:id
  });
}

【讨论】:

  • 这对 b.someMethodUsingSomeAPI 非常有用,但除非我搞砸了 CS,否则它在实例中不起作用。用结果更新了上面的示例。
  • 在对象字面量上定义新属性时,请删除= 以支持:,因为如果你不这样做,它绝对没有意义,而且我不知道 CS 到底如何不警告你。没有 new 的 B 的这些实例呢?您是否在其他方法中使用正确的语法调用 someMethodUsingSomeAPI,即 @someMethodUsingSomeAPI
  • 好的。我不知道为什么,但如果我将两者都放在构造函数中,我实际上有 console.log someMethodUsingSomeAPI '123' 工作。 B wit(out) new 似乎没有什么不同。只返回一个新的,除非已经是 B 的实例,如构造函数中所述。如果我做console.log @someMethodUsingSomeAPI '123',我会得到TypeError: Object #&lt;Object&gt; has no method 'someMethodUsingSomeAPI'
  • 您需要编辑代码并删除省略号,以向我们展示您实际测试的对象。告诉我们 console.log 的结果并没有什么帮助,因为我们不知道执行的上下文。
  • 这是完整的代码,我不确定我能否比我在介绍中更简洁地描述这个问题。同样,someMethodUsingSomeAPI 如果两者都在构造函数内部,则在从同一级别方法调用时有效,其中(@)someAPI 如果要使用这些动态凭据,则似乎必须同时声明和实例化。 someMethodUsingSomeAPI 如果它们不在构造函数中,则从同级方法调用时不起作用,因为 (@)someAPI 未定义,或者如果在构造函数之外声明,则没有 get 方法。跨度>
【解决方案3】:

根据您在此处提供的简化示例,该版本应符合您的要求:

class SomeClass
  # Store the last created instance at the class level
  lastInstance: null

  constructor: (options = {}) ->
    @someLastName = options.someLastName 
    # In constructor, the created instance is now the lastInstance
    SomeClass.lastInstance = this

# The helper method is not created in the class scope
someMethod = (someFirstName) ->
  "Hello " + someFirstName + " " + SomeClass.lastInstance.someLastName

someClass = new SomeClass({ someLastName: 'Borgnine' })

alert someMethod 'Ernest'

还有here's a link to try it in a browser

基本上,由于您希望您的辅助方法访问该类的实例,因此您需要提供对该实例的引用,该实例可以在某个时候引用。在这里,我使用一个类变量来存储最后创建的实例,并且助手在调用时访问最后一个实例。这意味着当创建许多实例时,它将执行如下:

someClass = new SomeClass({ someLastName: 'Borgnine' })

alert someMethod 'Ernest' # Hello Ernest Borgnine

someClass = new SomeClass({ someLastName: 'Doe' })

alert someMethod 'Boris' # Hello Boris Doe

【讨论】:

    猜你喜欢
    • 2020-10-15
    • 1970-01-01
    • 2012-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-17
    相关资源
    最近更新 更多