проблема javascript с пространством имен, " это " и библиотекой


Я создаю страницу визуализации (с помощью dc.js), для которой я решил сделать прыжок и собрать все это в единое пространство имен. Исходя из простоты Python, столкновение с безумием scope JavaScript было достаточно жестким, поэтому, пожалуйста, потерпите меня.

У меня есть общая структура JS следующим образом:

var NamespaceClass = function() {

    this.var0 = "something";
    this.var1 = dc.SomeChartClass("#some-css-selector");

    this.setup = function(error, config, dataset) {
        console.log("Inside setup:", this);
        this.var2 = this.process_data(dataset);
        // Do some more stuff...
    }

    this.process_data = function(data) {
        var whatever;
        //Do stuff with "data"...
        return whatever;
    }

    this.start = function() {
        console.log("Inside start:", this);
        var q;

        q = queue().defer(d3.json, "config.json")
                   .defer(d3.csv, "data.csv");
        q.await(this.setup);
    }
}

var MyNamespace = new NamespaceClass();
MyNamespace.start();

Где queue - это lib очереди Майка Бостока для асинхронной очереди файлов. Когда я пытаюсь протестировать скрипт, я получаю в консоли:

Inside start: Object { var0 = "something", var1={...}, more...}
Inside setup: Window testpage.html
TypeError: this.process_data is not a function

Итак, призывая setup from q.await делает его свободным от области видимости объекта (или как это называется в JavaScript...). Как мне этого избежать? Я также пытался использовать прокси-объект, такой как:

    this.start = function() {
        console.log("Inside start:", this);
        var q, proxy;

        q = queue().defer(d3.json, "config.json")
                   .defer(d3.csv, "data.csv");
        proxy = this.setup;
        q.await(proxy);
    }

Безрезультатно!

1 2

1 ответ:

Значение this определяется тем, как вы вызываете функцию, которая его содержит. Вы не можете контролировать, как вызывается функция setup, поскольку она вызывается внутри функции q.await.

Когда вы делаете q.await(this.setup), Вы передаете ссылку на настройку функции, но "теряете" любое соединение с вашим пространством имен. Вам нужно привязать функцию к пространству имен, чтобы она имела правильное значение this:

q.await(this.setup.bind(this));

Еще лучше, так как все ваши функции работают только в том случае, если this является пространством имен, вы следует привязать их к пространству имен следующим образом:

this.start = function() {
  // body
}.bind(this);

// usage:
q.await(this.setup);
И теперь, где бы вы ни проходили мимо них, они будут иметь правильный this внутри. Примечание: в этой ситуации bind работает примерно так:
this.start = function() {
    var namespace = this;

    q.await(function(){ namespace.setup(); });
}