为什么`this`指的是全局对象?

时间:2013-12-12 07:28:31

标签: javascript backbone.js coffeescript marionette

我有一个Backbone Marionette应用程序,下面定义了一个模块。当我运行此应用程序时,控制台日志语句打印出@作为窗口对象。运行list方法时,我认为this@)会引用List.Controller对象。我错过了什么?

###
The Header list controller.
###
define [
    'cs!app',
    'cs!./view',
    'cs!modules/header/entities'
], (
  App,
  View
) ->
  App.module 'Header.List', (List, App, Backbone, Marionette, $, _) ->
    List.Controller =
      list: ->
        console.log(@)
        headers = App.request 'header:entities'
        view = new View.Headers {collection: headers}
        App.headerRegion.show view

      setActiveHeader: (headerUrl) ->
        headers = App.request 'header:entities'
        header = headers.find (header) -> (header.get 'url') == headerUrl
        header.select()
        headers.trigger 'reset'

    App.commands.setHandler 'header:setActive', (headerUrl) ->
      List.Controller.setActiveHeader headerUrl

  App.Header.List.Controller

更新

这是调用list方法的模块:

###
The Header module.
###

define [
    'cs!app',
    'cs!./list/controller'
], (
  App,
  listController
) ->
  App.module 'Header', (Module, App, Backbone, Marionette, $, _) ->
    Module.startWithParent = false

  App.module 'Routers.Header', (ModuleRouter, App, Backbone, Marionette, $, _) ->
    class ModuleRouter.Router extends Marionette.AppRouter
      appRoutes: {}

      executeAction = (action, args) ->
        action(args)

      API =
        list: ->
          executeAction listController.list

      App.Header.on 'start', ->
        API.list()

      App.addInitializer ->
        new ModuleRouter.Router {listController: API}

  App.Header

3 个答案:

答案 0 :(得分:2)

问题是调用对象list的方法listController,其上下文为window(全局)。

之所以发生这种情况,是因为您通过这种方式调用了方法:executeAction listController.list而来自executeAction这只是方法调用方法:action(args)

您可以将方法绑定到类(使用_.bind)或使用js call的{​​{1}}或apply方法(绑定方式更容易):

绑定(Function

_.bind(action, context)

使用其他上下文(executeAction _.bind(listController.list, listController) method.call(context, arg1, ..)

调用(或应用)
method.apply(context, argsArray)

答案 1 :(得分:1)

你应该在初始化函数中使用_.bindAll(this),只需添加:

initialize:->
  _.bindAll(this, "list") // Like @mu mentioned in the comment, function name is required

修改

虽然@ KiT-O是正确的,但调用者可以使用_.bind函数将函数绑定到Controller。这不应该是调用者的责任,函数需要绑定到正确的上下文,调用者不应该关心/知道它。

这就是为什么我更喜欢_.bindAll解决方案,尽管它为Backbone添加了更多的样板代码

答案 2 :(得分:0)

this在调用函数之前不受约束,并且取决于函数的调用方式。您可以将其视为隐式传递给函数的额外参数。

在这种情况下,我认为您正在使用controller()调用您的函数。 this值可以通过调用函数作为方法(如foo.bar()foo["bar"]())或通过call()apply()显式设置来设置。你的调用都没有,所以这会恢复为全局对象。

来自here