【问题标题】:Access Instance-property in Coffeescript within nested在嵌套内访问 Coffeescript 中的实例属性
【发布时间】:2014-12-31 00:12:44
【问题描述】:

所以我在节点应用程序中使用 express。随着我的应用程序变得越来越大,我想将我的路线放入额外的文件中。如果我只是摆脱中间的 get 对象,我似乎能够掌握 bugDB。但我无法访问内部对象中的 bugDB。有什么建议么?也许还有一个更好的代码模式可以更优雅地完成这一点。

我希望得到您的帮助。提前致谢。 (因为我不是母语人士,我找不到其他有类似问题的人,如果你知道如何更好地表达这个问题,请告诉我方法:))

BUGROUTER.COFFEE
class BugsRouter
    constructor: (@bugDB)->   // instance-variable with databaselink
        return

    get:{
        allBugs: (req, res)=>
            console.log "db", @bugDB // this gives me undefined
                                     // is "this" in the get context? 
            @bugDB.allDocs {include_docs: true}, (err, response)->
                res.json 200, response
        }
module.exports = BugsRouter

SERVER.COFFEE
BugsRouter = require "./routes/BUGROUTER"
bugsRouter = new BugsRouter(bugDB)
console.log bugsRouter.bugDB # this is working
app.get    "/bugs/all", bugsRouter.get.allBugs

【问题讨论】:

    标签: express coffeescript


    【解决方案1】:

    子对象不是这样工作的。当你这样说时:

    class C
        p:
            f: ->
    

    那么p 只是一个普通对象,恰好是C 原型上的一个属性,它不会特别知道@ 应该在f 中是什么。如果您尝试改用粗箭头:

    class C
        p:
            f: =>
    

    那么你不小心创建了一个名为 f 的命名空间类函数,所以当调用 f 时,@ 将是 C。无论哪种情况,说:

    c = new C
    c.p.f()
    

    等同于:

    c = new C
    p = c.p
    p.f()
    

    所以f 将在p 而不是c 的上下文中调用。

    如果您不介意在调用 constructor 时手动绑定 get 中的函数,则可以解决此问题:

    constructor: (@bugDB) ->
        @get = { }
        for name, func of @constructor::get
            @get[name] = func.bind(@)
    

    这假设您有Function.bind 可用。如果您不这样做,那么您可以使用任何其他绑定技术(_.bind$.proxy、...)。需要@get = { } 技巧以确保您不会意外修改原型版本的@get;如果您确定您只会创建一个 BugsRouter 实例,那么您可以改用它:

    constructor: (@bugDB) ->
        for name, func of @get
            @get[name] = func.bind(@)
    

    get的原型版本中绑定函数,而不是实例的本地副本。

    您可以观看这个简化的演示以了解@ 在各种情况下的情况,密切关注@flag 的值以查看由于未使用@get = { }@constructor::get 导致的意外原型修改:

    class C1
        get:
            f: -> console.log('C1', @)
    
    class C2
        get:
            f: => console.log('C2', @)
    
    class C3
        constructor: ->
            @flag = Math.random()
            for name, func of @get
                @get[name] = func.bind(@)
        get:
            f: -> console.log('C3', @)
    
    class C4
        constructor: ->
            @flag = Math.random()
            @get  = { }
            for name, func of @constructor::get
                @get[name] = func.bind(@)
        get:
            f: -> console.log('C4', @)
    
    for klass in [C1, C2, C3, C3, C4, C4]
        o = new klass
        o.get.f()
    

    以上直播版:http://jsfiddle.net/ambiguous/8XR7Z/

    【讨论】:

    • 因为我还不能投票(我会尽快投票):thumbsup 感谢您的详尽解释!这对我很有帮助。
    • 那么您会建议尽可能避免使用子对象吗?我喜欢它们的模块化
    • @Gundon 您可以根据需要使用它们,但您必须在某处手动绑定它们,并且您需要记住绑定它们不是免费的。真的只是通常的权衡问题。
    【解决方案2】:

    嗯,看来我终于找到了更好的解决方案:

    class Test
        constructor: ->
            @testVariable = "Have a nice"
            return
    
        Object.defineProperties @prototype,
            get:
                enumerable :true
                get:->
                    {
                        day: => @testVariable + " day"
                        week: => @testVariable + " day"
                    }
    
    console.log (new Test()).get.day()
    

    这允许我以我想要的方式拨打(new Test()).get.day()。 现场版在:JSFiddle

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-12
      • 2015-01-01
      • 2016-09-14
      • 2020-08-25
      相关资源
      最近更新 更多