OO Javascript - правильная обработка контекста? - PullRequest
0 голосов
/ 16 апреля 2011

Я написал короткий и неполный пример (ради этого вопроса), который пытается использовать jquery для суммирования ширины группы изображений.У меня есть некоторые проблемы с выяснением того, как обрабатывать область видимости в сложных OO-приложениях javascript.

function imageContainer(){
      this.selector = "img.inContainer";

      this.width = function(){
        var tmp = 0;
        $(this.selector).each(function(){
          // use load to preload images
          $(this).load(function(){ 
             // our 'this' pointer to the original object is long gone,
             // so is it even possible to accumulate a sum without using
             // globals? Ideally, I'd like to increment a temporary value
             // that exists within the scope of this.width();
             tmp+=$(this).width();
          });
        });
        // I'm thinking that returning here is problematic, because our
        // call to each() may not be complete?
        return tmp;
      }

      this.construct = function(){
        alert(this.width());
      }

      this.construct();
}

Я на самом деле не ищу взломать эту проблему, я хотел бы знать, как этот видвещь должна быть выполнена - способом, который не разрушает инкапсуляцию.Я что-то упускаю из виду?

Большое спасибо.

1 Ответ

3 голосов
/ 16 апреля 2011
function imageContainer() {
    this.selector = "img.inContainer";

    this.width = function(cb) {
        var tmp = 0;
        var len = this.length;
        var count = 0;
        $(this.selector).each(function() {
            // use load to preload images
            var that = this;
            // load is ajax so it is async
            $(this).load(function() {
                tmp += $(that).width();
                if (++count === len) {
                    // counted all.
                    cb(tmp);
                }
            });
        });
    };

    this.construct = function(cb) {
        this.width(function(data) {
            alert(data);
        });
    };

    this.construct();
}

Добро пожаловать в ajax.Вы выполняете кучу операций параллельно асинхронно.Таким образом, вам нужно отслеживать, сколько завершено, и запускать обратный вызов, когда все завершено.

Любая асинхронная операция, такая как .load, требует, чтобы вы либо блокировали на 100 секунд мс, либо изменили свой API для использования обратных вызовов.

Вместо шаблона var that = this, который вы используетевместо этого также можно использовать $.proxy.

// load is ajax so it is async
$(this).load($.proxy(function() {
    tmp += $(this).width();
    if (++count === len) {
        // counted all.
        cb(tmp);
    }
}, this));

Поскольку у вас есть конструкция, позволяющая выполнить n ajax-задач перед запуском обратного вызова, вы можете обобщить это с помощью небольшого количества сахара.

this.width = function(cb) {
    // map all images to deferred objects, when deferred objects are resolved
    $.when($.makeArray($(this.selector).map(function() {
        var def = $.Deferred();
        $(this).load(function() {
            def.resolve();
        });
        return def;
    // then sum the widths and fire the callback.
    }))).then($.proxy(function(data) {
        var tmp = 0;
        $(this.selector).each(function() {
             tmp+=$(this).width();
        });
        cb(tmp);
    }, this));
};

Обратите внимание, здесь я действительно хочу использовать $.fn.reduce, но он не существует.Это могло бы быть

// reduce the set of images to the sum of their widths.
cb($(this.selector).reduce(0, function(memo, key, val) {
    return memo + $(this).width();
}));

Если подумать, этот сахар не упрощает его, по крайней мере, теперь он больше похож на LISP, чем на C.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...