从回调函数中访问`this`

4

类似的问题已经在这里How do I trigger the success callback on a model.save()?被提出,但仍然没有回答如何从回调中触发事件。

所以这是我代码中的success回调,在其中我想调用addOne事件来渲染保存的评论。除了this.addOne(receivedItem);之外,一切都运行良好 - 我无法在回调中使用this来触发此事件。在其他地方 - 我可以。

如何解决这个问题?

CommentsListView = Backbone.View.extend({
    ...
    addOne: function (item) {
        var commentView = new CommentView({
            model: item
        });
        this.$el.append(commentView.render().el);
    },
    addNewComment: function (event) {
        var item = {
            post_id: this.$('#post_id').val(),
            text: this.$('#text').val()
        };
        var commentItem = new CommentItem();
        commentItem.save({'model':item}, { 
            success: function(receivedItem, response) {
                this.addOne(receivedItem); // Uncaught TypeError: Object [object Window] has no method 'addOne'.
            }
        }, this);
    }
});

2
可能是重复的问题:如何在回调函数中访问正确的“this”/上下文?(https://dev59.com/v2Ij5IYBdhLWcg3wb0jX) - Bergi
2个回答

9

这是因为成功回调函数有不同的作用域,this 指向的不是你的视图。
为了快速解决这个问题,只需要引用 this 并使用它即可:

var self = this;
commentItem.save({'model':item}, { 
    success: function(receivedItem, response) {
        self.addOne(receivedItem); // works
    }
});

或者你可以使用underscore的bind方法来将不同的上下文绑定到一个函数中:

success : _.bind(function(receivedItem, response) {
    this.addOne(receivedItem); 
}, this)

你真是个天才!它起作用了!而且它对其他人也有用 - 我花了几个小时来解决这个问题(我在 JavaScript 方面还不太好) :) - Gediminas Šukys
@MdaG,您是在指underscore的bind方法吗? - gion_13
不,我的意思是将“this”作为一个附加参数如何使它起作用?我这里有一个知识盲点,因为我在其他代码中也看到过它被使用。 - MdaG
@MdaG 这就是 underscore 的 bind 函数所做的事情。它接受两个参数:一个函数和一个对象,并返回一个以指定对象为作用域的新函数。这类似于 es5 中函数的标准 bind 方法:var getFoo = function (){return this.foo;}.bind({foo:'bar'})。你可能应该阅读文档来弥补这个空白 :) - gion_13
看文档 :) 理解bind(或者说我理解了吗?),但我指的是你的第一个例子,在其中将“this”作为第三个参数发送到save。根据文档,它只接受两个参数。http://backbonejs.org/#Model-save - MdaG
1
@MdaG 很抱歉之前我没有理解你的意思。你是对的:model.save 只需要两个参数。我真的不记得第三个参数是怎么进入这个函数调用的(因为这个答案有一段时间了)。它是不必要的和误导性的,我为此道歉。无论如何,通过在 self 变量中使用对 this 的引用来保留上下文。也更新了答案。谢谢 - gion_13

0
这可能是一个晚回答,但会帮助正在寻找答案的人。这是从settimeout回调中访问“this”关键字。
CommentsListView = Backbone.View.extend({
...
    addOne: function (item) {
        // DO Stuff
    },
    addNewComment: _.bind(function (event) {
        setTimeout(_.bind(function(){ 
            this.addOne(/*receivedItem*/);
        }, this), 1000);
    }, this)
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接