此关键字丢失了对当前模块的引用

时间:2014-10-25 07:35:27

标签: javascript jquery backbone.js

我正在研究BackboneJS模块。在视图中,我将插件应用于当前元素。我正在传递一个选项对象setOptions,它被设置为当前视图的属性。在这个对象中,我也调用了一个函数this.foo。但它给了我以下错误:foo of undefined。以下是我的代码。

var b = Backbone.View.extend({

    setOptions: {
        opt1: 'Option 1',
        opt2: 'Option 2',
        opt3: 'Option 3',
        opt4: 'Option 4',
        callback: this.foo // this returns foo of undefined
    },

    initialize: function () {
        this.setPlugin();
    },

    setPlugin: function () {
        this.$el.pluginName(this.setOptions);
    },

    foo: function () {
        console.log('FOO');
    }

});

为了解决这个问题,我写了一个函数setOptions。并返回设置插件选项的对象文字。这次函数this.foo成功调用,但在foothis的引用指向this.$el我希望此关键字指向当前模块而不是该元素。我需要这个,因为我想在foo内调用更多函数,但我不能更改此关键字的引用。 我该怎么做?

下面是我的第二次尝试代码

var b = Backbone.View.extend({

    initialize: function () {
        this.setPlugin();
    },

    setPlugin: function () {
        this.$el.pluginName(this.setOptions());
    },

    setOptions: function () {
        return {
            opt1: 'Option 1',
            opt2: 'Option 2',
            opt3: 'Option 3',
            opt4: 'Option 4',
            callback: this.foo
        }
    },

    foo: function () {
        // here "this" reference to this.$el but not current module
        console.log('FOO');
    }

});

2 个答案:

答案 0 :(得分:0)

问题是,在创建对象之前,您无法从同一对象引用对象的属性。因此,在构造视图对象并且它到达行callback: this.foo的情况下,在对象中尚未创建此类属性。因此错误。

最简单的解决方法是使用getter函数:

setOptions: function() {
    return {
        opt1: 'Option 1',
        opt2: 'Option 2',
        opt3: 'Option 3',
        opt4: 'Option 4',
        callback: _.bind(this.foo, this)
    }
},

并像这样使用它:

setPlugin: function () {
    this.$el.pluginName(this.setOptions());
},

答案 1 :(得分:0)

以下是发生的事情(查看评论):

// Fake "plugin" function.
function pluginName(options) {
  // Here I'm setting the 'this' value of 'foo' to the document body.
  options.callback.call(document.body);

  // Here the 'this' value would be the 'options' object because I'm calling 
  // the method through the 'options' object itself.
  /* options.callback(); */

  // If I did the following instead, the 'this' value of 'foo' would
  // be the global object, which is the 'window' object. That's because 
  // any function that's not called by a specific object is automatically 
  // executed in the context of the 'window' object.
  // var fn = options.callback;
  /* fn(); */
}

var view = {
  initialize: function () {
    this.setPlugin();
  },

  setPlugin: function () {
    pluginName(this.setOptions());
  },

  setOptions: function () {
    return {
      opt1: 'Option 1',
      opt2: 'Option 2',
      opt3: 'Option 3',
      opt4: 'Option 4',

      // 'foo' here is called by the plugin, and its 
      // 'this' value depends on how the plugin calls it.
      callback: this.foo
    }
  },

  foo: function () {
    console.log('FOO');

    // The 'this' value here depends on how the plugin calls 'foo'; in this example it is the document body.
    console.log(this);
  }
};

这是一个修复:

// Fake "plugin" function.
function pluginName(options) {
  options.callback.call(document.body);
}

var view = {
  initialize: function () {
    this.setPlugin();
  },

  setPlugin: function () {
    pluginName(this.setOptions());
  },

  setOptions: function () {
    return {
      opt1: 'Option 1',
      opt2: 'Option 2',
      opt3: 'Option 3',
      opt4: 'Option 4',

      // The 'bind' method creates an other callback for you, by making 
      // the 'this' value equal to whatever you pass it as the first argument.
      callback: this.foo.bind(this) // or use Underscore's '_.bind()' method as mentioned below.
    }
  },

  foo: function () {
    console.log('FOO');
    console.log(this); // 'this' here is the 'view' object.
  }
};

这是另一个修复:

// Fake "plugin" function.
function pluginName(options) {
  options.callback.call(document.body);
}

var view = {
  initialize: function () {
    this.setPlugin();
  },

  setPlugin: function () {
    pluginName(this.setOptions());
  },

  setOptions: function () {
    var self = this;

    return {
      opt1: 'Option 1',
      opt2: 'Option 2',
      opt3: 'Option 3',
      opt4: 'Option 4',

      // Similar to the 'bind' method but manually.
      callback: function() {
        self.foo();
      }
    }
  },

  foo: function () {
    console.log('FOO');
    console.log(this); // 'this' here is the 'view' object.
  }
};