11

我正在处理有关对象内部的 Ajax 回调的问题。请考虑以下代码:

Search.prototype =
{
    ask : function( query )
    {
        // Display loader
        $('.loader').show();

        $.ajax({
            dataType : 'jsonp',
            type : 'GET',
            url : 'http://api.deezer.com/search/track/',
            data : {
                output : 'jsonp',
                q : query
            }
        }).done(function(res) {

            this.loadResults( res );
            // [Error] Object success has no method 'loadResult'

        });
    },

    loadResults : function (res)
    {
        // Hide loader
        $('.loader').hide();

        console.log( res );

        // doing some stuff
        // ...
    }
}

var search = new Search();
search.ask( 'eminem' );

我收到一个错误Object success has no method loadResult,这是有道理的,因为回调是匿名 jQuery 函数的一部分。

但是如何获取我的初始对象实例?

我一直在尝试使用 var that = this; 在 Ajax 调用之前,但出于同样的原因,我不会工作。

我不知道是否可以这样做,或者问题是否来自我的代码全球组织。请随时向我提供有关最佳实践的建议:)

提前谢谢。

[更新(已解决)]

我在我的代码中混淆了一些东西,虽然我没有必要在这里发布,但我终于在我的代码中更早地发现了问题。对于那个很抱歉。

这是我的完整代码,现在正在运行:

define(['jquery'], function($) {

    var Search = function()
    {
        this._keyDownTimer = 0;
        this._searchDelay = 1000; // ms
    };

    Search.prototype =
    {
        // The init function that I though it was unnecessary to post here. Sorry :/
        init : function()
        {
            $('#q').on('keydown', (function(evt) {

                clearTimeout( this._keyDownTimer );

                this._keyDownTimer = setTimeout( (function() {

                    this.ask( $('#q').val() );

                }).bind( this ), this._searchDelay); /* <-- Here's the solution.
                                                        I forgot to bind `this`
                                                        to the timeout callback function,
                                                        so the `this` under all of my code
                                                        was referring to the anonymous function
                                                        of this callback. */

            }).bind( this ));
        },

        ask : function( query )
        {
            // Display loader
            $('.loader').show();

            console.log(this); // Now `this` refers to my object :)

            var req = $.ajax({
                dataType : 'jsonp',
                type : 'GET',
                url : 'http://api.deezer.com/search/track/',
                context : this,
                data : {
                    output : 'jsonp',
                    q : query
                }
            });

            req.done(function(res) {
                this.loadResults(res);
            });
        },

        loadResults : function (res)
        {
            // Hide loader
            $('.loader').hide();

            // doing some stuff
            // ...
        }
    };

    return new Search;

});

谢谢你的回复,真的很有帮助。

铅解决了。

4

3 回答 3

35

有几种方法可以做到这一点。

您可以设置contextajax 选项的设置:

jQuery.ajax context环境

$.ajax({
    context: this

Function.prototype.bind

    .done(function (res) {

    }.bind(this));

但是,这并不像...那样得到广泛支持

jQuery.proxy

为此目的而创建。

    .done($.proxy(function (res) {

    }, this);

将其分配给另一个值

var self = this;
$.ajax({
/* snip */
.done(function (res) {
    self.loadResults(res);

这通常在 JavaScript 中完成,以便this在较低范围内进行访问。

具有词法绑定的箭头函数

$.ajax({
/* snip */
.then(res => this.loadResults(res));
于 2013-10-09T14:26:30.747 回答
6

您可以在此处使用$.ajax() context对象,例如:

$.ajax({
    url : 'http://api.deezer.com/search/track/',
    context: this,
    ...
}).done(function (res) {
    this.loadResults( res );
});
于 2013-10-09T14:24:11.190 回答
3

可以使用 ES5.bind函数this正确设置:

$.ajax(...).done(this.loadResults.bind(this));

(在上面的链接中使用 shim,或者$.proxy在旧浏览器上使用 jQuery 等效项)。

或者,添加context: this$.ajax选项:

$.ajax({
    ...,
    context: this
}).done(this.loadResults);

请注意,在任何一种情况下,您都将覆盖 jQuery 将 ajax 选项对象传递到this.

ps 对链return的结果也是一种很好的做法,这样您的对象的用户可以将其他回调(例如处理程序)链接到它。$.ajax().fail

于 2013-10-09T14:22:30.877 回答