JavaScript闭包和范围的问题



我有一个名为writeMessage的函数。 writeMessage 调用 ajax 请求来获取本地化内容。 从 ajax 请求返回内容后,它还会在"n"秒后淡出消息。所以这一切都有效,我已经测试了许多调用,但是,我觉得它过于复杂,因为我在处理 javascript 闭包语句时并不完全了解变量的范围。谁能告诉我我在这里跳过了太多的箍来完成以下任务。

函数 getTextResource 采用参数(字符串、字符串、对象、函数(

  • 'function' 参数是一个回调,一旦 ajax 调用请求已完成。
  • "对象"参数是一个参数对象,包含所有有关应如何以及在何处编写消息的详细信息。
  • "字符串">
  • 和"字符串"参数正在传递到AJAX中。请求。

在getTextResource中,我正在调用一个ajax方法,该方法将"object"参数作为上下文以及原始默认文本和回调函数传递一旦 ajax 请求完成,我现在通过上下文调用回调函数,将服务调用的结果和参数传递给它。

我是否需要继续传递上下文,或者如果再次调用函数,传递给 getTextResoruce 的所有内容是否安全,不会被分配不同的值?

function writeMessage(args) {
    var d = $('<div></div>');
    getTextResource(args.resourceId, args.message, { args: args, messageElement: d },
        function (text, context) {
            var args = context.args;
            var d = context.messageElement;
            d.empty();
            d.append(text);
            args.element.append(d);
            if (args.fadeTimeOut > 0)
                setTimeout(function () {
                    d.fadeOut('slow', function () {
                        $(this).remove();
                    });
                }, args.fadeTimeOut);
        }
    );
}
var getTextResource = function (resourceId, defaultText, context, cb) {
    resourceId = resourceId + '';
    defaultText = defaultText + '';
    if (resourceId == '') resourceId = defaultText;
    if (defaultText == '') defaultText = resourceId;
    try{
        var request = $.ajax({
            type: 'GET',
            url: 'http://localhost/EaiCCM/api/' + BusinessScope.Version + '/' + BusinessScope.CampaignSegment + '/TextResource',//?' + qs,
            data:  {ResourceId: resourceId, DefaultText: defaultText},
            cache: false,
            dataType: 'json',
            contentType: 'application/json; charset=utf-8',
            context: { defaultText: defaultText, context: context, cb: cb }
        });
        request.done(function (result) {
            var txt = this.defaultText;
            try {
                if ($.isPlainObject(result))
                    txt = result.Detail;
            }
            catch (e) {
            }
            finally {
                if (typeof this.cb == 'function')
                    this.cb(txt, this.context);
            }
        });
        request.fail(function (jqXHR, textStatus, context) {
            if (typeof this.cb == 'function')
                this.cb(this.defaultText, this.context);
        });
    }
    catch (e) {
        if (typeof cb == 'function')
            cb(defaultText, context);
    }
};

不,如果您在 writeMessage 范围内构造回调,则不需要回调的context对象。(作用域是函数的每个调用的本地范围。

这:

    function (text, context) {
        var args = context.args;
        var d = context.messageElement;

同样容易:

    function (text) {

request.done可以阅读:

    request.done(function (result) {
        var txt = defaultText;
        try {
            if ($.isPlainObject(result))
                txt = result.Detail;
        }
        catch (e) {
        }
        finally {
            if (typeof cb == 'function')
                cb(txt);
        }
    });
参数

的作用域为它们作为参数的函数的每个调用。 var变量的作用域为 var 语句上方第一个function的调用。范围仅持续到关闭该function的大括号。

因此,在此代码中:

function writeMessage(args) {
  var d = $('<div></div>');
  var rid = args.resourceId;
  var cb = function (text) {
    var exampleVar = text.toUpper();
    d.textContent = exampleVar + rid;
  }
  getTextResource(rid+'-san', 'foo', cb)
  getTextResource(rid+'-chan', 'bar', cb)
}
function getTextResource(resourceId,defaultText,cb) {
  // for simplicity's sake let's just simulate a default scenario
  // Note that the `resourceId` passed to `getTextResource`
    // is in no way passed to the callback here
  cb(defaultText);
}
  • argsridd 是每个writeMessage调用的本地。
  • textexampleVar 是回调cb的每个调用的本地 。
  • resourceIddefaultText 是每个getTextResource调用的本地 。
  • cb是我们在writeMessage中构造的回调,以及我们在getTextResource中传入的回调。尽管它们具有相同的名称,但不同的作用域意味着它们实际上被视为两个不同的变量。(如果这令人困惑,请参阅下面的类比。
  • getTextResource'bar'调用回调时,它将修改与调用'foo'回调时相同的d,因为回调中使用的d是构造它的writeMessage的本地。
  • 但是,dtextContent设置的 exampleVar 值在每个调用中会有所不同,因为它是回调的本地值。
  • exampleVar 的值不会以额外的'-san''-chan'结尾,因为它们被附加到 getTextResource 范围内的resourceId,而范围对writeMessage的范围是不可见的(其中变量被称为 rid,无论如何都不resourceId(。

不同作用域中同名变量的类比

变量名称在不同的上下文中引用不同的值,例如"Bob"在Bob's Burgers中表示与在Bob the Builder中不同的人。然而,在一个上下文中,"鲍勃"有可能指的是在其原始上下文中也称为"鲍勃"的东西,例如在弓箭手第 4 季的第一集中,斯特林被称为"鲍勃"并在"鲍勃汉堡"工作(作为参考 H. Jon Benjamin 为两个角色配音(。你可以说这是一个巧合,"真正的"鲍勃汉堡"鲍"存在于弓手世界的其他地方,但无论他在两个上下文中是否是同一个"鲍勃",都与他从弓箭手的一个场景到下一个场景是同一个"鲍勃"无关紧要。