为什么“this”指的是全局对象

Why does `this` refer to the global object?

本文关键字:全局 对象 this 为什么      更新时间:2024-06-29

我有一个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

更新

这是调用列表方法的模块:

###
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

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

之所以发生这种情况,是因为您以这种方式调用方法:executeAction listController.list,而从executeAction调用方法只是以正常方式:action(args)

您可以将方法绑定到类(使用_.bind),也可以使用js Functioncallapply方法(绑定方式更容易):

绑定(_.bind(action, context):

executeAction _.bind(listController.list, listController)

使用另一上下文(method.call(context, arg1, ..)method.apply(context, argsArray))调用(或应用)

  executeAction = (context,action, args) ->
    action.call(context, args)
  API =
    list: ->
      executeAction listController, listController.list

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

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

编辑

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

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

this在函数被调用之前不会被绑定,并且取决于函数的调用方式。您可以将其视为隐式传递给函数的一个额外参数。

在这种情况下,我认为您正在使用controller()调用您的函数。通过调用函数作为方法(如foo.bar()foo["bar"]())或通过call()apply()显式设置this值。您的调用既不执行也不执行,因此这将恢复为全局对象。

从这里开始。