2015-05-10 4 views
-1

Я пытаюсь назначить объект прототипу, но я продолжаю получать ошибку, что объект не определен. Я пытаюсь сделать этоНазначение объекта прототипу

//x.prototype.y = {}; 
StreetEasy.prototype.neighborhoodPaths = {}; 

и на более позднем этапе в коде я пытаюсь получить доступ к этому объекту в другой функции прототипа и нажмите на новых данных с

//x.prototype.assignData = function(z, a){ 
    // this.y[z] = a; 
//} 
StreetEasy.prototype.findNeighborhoodPath = function(areaQuery, callback){ 
    var data = {q: areaQuery, key: this.apiKey, format: this.format}; 
    var query = qs.stringify(data); 
    var url = AreaSearchUrl + '?' + query; 

    var areaQ = areaQuery.toLowerCase(); 
    if (this.neighborhoodPaths[areaQ]) { 
     callback(this.neighborhoodPaths[areaQ].path); 
    } else { 
     http.get(url, function(response){ 
     response.setEncoding('utf8'); 
     response.on('data', function (rData){ 
      rData = JSON.parse(rData); 
      callback(rData); 
      rData.areas.every(function(element){ 
    -----------error is here-> this.neighborhoodPaths[element.name.toLowerCase()].path = element.path; 
      }); 

     }).on('error', function(e){ 
       console.error('ERROR: ' + e.message + ' | ' + e.statusCode); 
     }); 
    }); 
    } 
}; 

узел продолжает возвращаться

TypeError: Невозможно прочитать свойство z ​​неопределенного. Что я делаю не так?

Редактировать больше кода:

StreetEasy.prototype.neighborhoodPaths = {}; 
StreetEasy.prototype.findNeighborhoodPath = function(areaQuery, callback){ 
    var data = {q: areaQuery, key: this.apiKey, format: this.format}; 
    var query = qs.stringify(data); 
    var url = AreaSearchUrl + '?' + query; 

    var areaQ = areaQuery.toLowerCase(); 
    if (this.neighborhoodPaths[areaQ]) { 
     callback(this.neighborhoodPaths[areaQ].path); 
    } else { 
     http.get(url, function(response){ 
     response.setEncoding('utf8'); 
     response.on('data', function (rData){ 
      rData = JSON.parse(rData); 
      callback(rData); 
      rData.areas.every(function(element){ 
    -----------error is here-> this.neighborhoodPaths[element.name.toLowerCase()].path = element.path; 
      }); 

     }).on('error', function(e){ 
       console.error('ERROR: ' + e.message + ' | ' + e.statusCode); 
     }); 
    }); 
    } 
}; 
+1

Я не мог» t воспроизвести проблему. Пожалуйста, покажите фактический код. – thefourtheye

+1

Что такое переменная 'x'? – jfriend00

+0

Возможно, x не является функцией или вы передаете assignData как обработчик обратного вызова/события. Как использовать прототип и значение этого объясняется здесь: http://stackoverflow.com/a/16063711/1641941 вы можете попробовать несколько консольных журналов, чтобы увидеть больше результатов (например, console.log (this)) – HMR

ответ

3

(см обновление ниже, теперь, когда Вы разместили код.)

Это, скорее всего, является результатом того, как вы звоните assignData. Это будет работать, например:

var obj = new x(); 
obj.assignData("foo", "bar"); 

Это не так:

var obj = new x(); 
f = obj.assignData; 
f("foo", "bar"); 

И по той же причине, что это не будет:

callMeBack(obj.assignData, "foo", "bar"); 
function callMeBack(method, z, a) { 
    method(z, a); 
} 

В обоих случаях проблема заключается в том, что this в вызове assignData не относится к объекту, вместо этого он является глобальным объектом. Когда вы вызываете функцию не через ссылку на свойство, this устанавливается на глобальный объект (в свободном режиме, в строгом режиме это будет undefined). Это действие вызова его через ссылку собственности, которая устанавливает this объекту собственности.

Больше (в моем блоге):


Update, теперь, когда Вы разместили код. Я собираюсь предположить, что findNeighborhoodPath - это функция, которую вы назвали assignData в своем исходном вопросе.

Проблема в том, что вы теряете this, но не совсем так, как показано выше.

Обратный вызов, который вы передаете http.get, будет вызван с this, ссылаясь на глобальный объект, а не на экземпляр, на который был вызван findNeighborhoodPath; аналогично, обратный вызов, который вы передаете в Array#every, будет иметь this, ссылаясь на глобальный объект, потому что вы не сказали ему делать что-то еще.

Если вы хотите использовать этот экземпляр, самый простой способ, чтобы объявить переменную со ссылкой на него, а затем использовать переменную:

var self = this; // <== Variable to remember `this` 
http.get(url, function(response) { 
    response.setEncoding('utf8'); 
    response.on('data', function(rData) { 
     rData = JSON.parse(rData); 
     callback(rData); 
     rData.areas.every(function(element) { 
      self.neighborhoodPaths[element.name.toLowerCase()].path = element.path; 
     // ^^^^ --- using it 
     }); 

    }).on('error', function(e) { 
     console.error('ERROR: ' + e.message + ' | ' + e.statusCode); 
    }); 
    // ... 
}); 

Кроме того, вы могли бы использовать Function#bind и thisArg аргумент Array#every:

http.get(url, function(response) { 
    response.setEncoding('utf8'); 
    response.on('data', function(rData) { 
     rData = JSON.parse(rData); 
     callback(rData); 
     rData.areas.every(function(element) { 
      this.neighborhoodPaths[element.name.toLowerCase()].path = element.path; 
     }, this); // <=== Note passing `this` as the second arg to `every` 

    }).on('error', function(e) { 
     console.error('ERROR: ' + e.message + ' | ' + e.statusCode); 
    }); 
    // ... 
}.bind(this)); // <=== Note the .bind(this) 

В следующей версии JavaScript, ECMAScript6, мы будем иметь «жир» стрелка функции, которые имеют «лексической this, «причудливый термин означает, что this в функции будет такой же, как this был в контексте, в котором была создана функция. Поэтому, как только V8 поддерживает их, и обновления узлов к использованию этой версии V8 (оба эти будут довольно скоро), вы будете в состоянии сделать это (обратите внимание на два => ниже):

http.get(url, (response) => { 
    response.setEncoding('utf8'); 
    response.on('data', function(rData) { 
     rData = JSON.parse(rData); 
     callback(rData); 
     rData.areas.every((element) => { 
      this.neighborhoodPaths[element.name.toLowerCase()].path = element.path; 
     }); 

    }).on('error', function(e) { 
     console.error('ERROR: ' + e.message + ' | ' + e.statusCode); 
    }); 
    // ... 
}); 
+0

Спасибо. Есть ли другие способы передать правильное «это»? Было бы более эффективным использовать http.get.bind (это)? –

+0

@MikeF: Маловероятно, используете ли вы вещь 'self' или' Function # bind' и аргумент 'thisArg' для' Array # every' (я добавил пример, если вы хотите это сделать), эффективность этого кода будет зависеть от операции HTTP, а не от JavaScript. Мой инстинкт заключается в том, что если вы хотите микро-оптимизировать (что я не рекомендую), наиболее эффективной будет «var paths = this.neighborhoodPaths;» перед вызовом 'http.get', а затем' paths [ element.name.toLowerCase()]. ​​path = element.path; 'в обратном вызове' every'. Но я очень сомневаюсь, что это будет иметь значение в реальном мире. –

Смежные вопросы