2014-02-11 3 views
2

Я строю страницу визуализации (с dc.js), для которой я решил сделать прыжок и собрать все это в одно пространство имен. Исходя из простоты Python, сбой с безумием области JavaScript был достаточно жестким, поэтому, пожалуйста, несите меня.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 является Mike Bostock's queue lib для асинхронного файла очереди. Когда я пытаюсь проверить сценарий, я получаю в консоли:

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

Таким образом, применение setup из 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); 
    } 

не имеет никакого отношения!

+0

Это не связано с вашей проблемой, но нет никакой необходимости, чтобы создать класс, чтобы иметь пространство имен. Простой объект будет выполнен, вы можете инициализировать его с помощью IIFE, чтобы все ваши переменные были скопированы, чтобы они не загрязняли глобальную область. – Tibos

+0

Это единственный способ, который позволил мне выполнять вызовы между классами (например, 'this.fun1', вызывающий' this.fun2'). Но это утомительно, используя 'this.' каждый раз. Не могли бы вы указать на некоторые примеры того, что вы предлагаете? –

+0

В этом [ответе] (http://stackoverflow.com/a/5647397/1669279) приведен пример. – Tibos

ответ

2

Значение 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(); }); 
} 
+0

Мне пришлось использовать '.bind (namespace)' (где 'namespace' соответствует вашему последнему примеру) для анонимных функций, объявленных в рамках свободно используемых методов (например,' dc.js') внутри методов класса. –