javascript闭包和范围问题

时间:2013-03-02 17:02:52

标签: javascript scope closures

我有一个名为writeMessage的函数。 writeMessage调用ajax请求以获取本地化内容。一旦从ajax请求返回内容,它也会在'n'秒后消除消息。 所以这一切都有效,我已经测试了一些调用,但是,我觉得它过于复杂,因为我在处理javascript闭包语句时并不完全理解变量的范围。 任何人都可以告诉我,如果我在这里跳过太多的箍来完成下面的工作。

函数 getTextResource 接受参数,(字符串,字符串,对象,函数)

  • 'function'参数是一个在ajax上调用的回调 请求已完成。
  • 'object'参数是一个包含所有的参数对象 有关如何以及在何处写入消息的详细信息。
  • 'string'& 'string'参数正在传递给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);
    }
};

1 个答案:

答案 0 :(得分:0)

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

此:

    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变量的范围限定为function语句上方第一个var的调用。 范围仅在关闭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);
}
  • argsriddwriteMessage每次调用的本地。
  • textexampleVar是回调cb每次调用的本地。
  • resourceIddefaultTextgetTextResource每次调用的本地。
  • cb是我们在writeMessage中构建的回调,以及我们在getTextResource中传递的回调。尽管它们具有相同的名称,但不同的范围意味着它们有效地被视为两个不同的变量。 (如果这令人困惑,请参阅下面的类比。)
  • getTextResource使用'bar'调用回调时,它会修改与调用d的回调时相同的'foo',因为使用了d在回调中是构造它的writeMessage的本地回送。
  • exampleVar textContent设置为d的{​​{1}}值在每次调用时都会有所不同,因为它在回调本地。
  • exampleVar的值'-san''-chan'结尾,因为它们会附加到范围中的resourceId getTextResource的{​​{1}},writeMessage的范围无法看到(无论如何,变量被称为rid而不是resourceId。)

对不同范围内具有相同名称的变量的类比

变量名称指的是不同上下文中的不同值,例如“Bob”表示 Bob's Burgers 中的不同人,而不是 Bob the Builder 中的人。但是,在一个上下文中,“Bob”可能会在其原始上下文中引用一些也被称为“Bob”的内容,就像第一季 Archer 第4季中Sterling被称为“Bob” “并在”Bob's Burgers“工作(作为H. Jon Benjamin的参考,为两个角色提供声音)。你可以声称这是巧合而且“真正的” Bob's Burgers “Bob”存在于 Archer 世界的其他地方,但他是否是同一个“Bob”从 Archer 中的一个场景到下一个场景,两个上下文与他是同一个“Bob”无关。