1

Я новичок в программировании JavaScript, и я даже не знаю, как спросить Google, поэтому я подробно расскажу о том, чего бы я хотел достичь.Как переписать свойство constructor из функции

Я использую Node.js и xml2js модуль для создания DataProvider класс для жасмин, что разобрать простой XML-файл:

<Tests> 
    <Test name="test1"> 
     <values>2,4,6</values> 
     <expectations>1,2,3</expectations> 
    </Test> 
    <Test name="test2"> 
     <values>8,10,12</values> 
     <expectations>4,5,6</expectations> 
    </Test> 
</Tests> 

Я хотел бы DataProvider конструктор немедленно разобрать XML и есть результат, видимую в this.testData. Сценарий:

var fs = require('fs'), 
    xml2js = require('xml2js'), 
    util = require('util'); 

var DataProvider = function(dataPath) { 
    this.dataPath = dataPath; 
    this.testData; 

    fs.readFile(this.dataPath, function(err, data) { 
     var parser = new xml2js.Parser(); 
     parser.parseString(data, function(err, result) { 
      //console.log(util.inspect(result, false, null)); 
      this.testData = result; 
     }); 
    }); 
}; 

Я использую это нравится следующим образом:

var dp = new DataProvider("C:\\data2.xml"); 
console.log(dp.testData); 

Когда я бегу сценарий >node script.js Я получаю undefined. Когда я раскомментировать console.log(util.inspect(result, false, null)); Я получаю

undefined 
{ Tests: 
    { Test: 
     [ { '$': { name: 'test1' }, 
      values: [ '2,4,6' ], 
      expectations: [ '1,2,3' ] }, 
     { '$': { name: 'test2' }, 
      values: [ '8,10,12' ], 
      expectations: [ '4,5,6' ] } ] } } 

так вообще это работает, но как назначить result для this.testData?

Связано это с областью this.testData?

+0

возможного дубликата [Получить данные из фс. readFile] (http://stackoverflow.com/questions/10058814/get-data-from-fs-readfile) – hugomg

+0

Согласно [этому аналогичному вопросу] (http://stackoverflow.com/questions/10058814/get-data- from-fs-readfile), вы можете использовать 'readFileSync' вместо' readFile'. Однако это противоречит асинхронности node.js - вам может потребоваться изменить интерфейс на что-то с помощью async 'init' metho d вместо связывания всего в конструкторе. – hugomg

ответ

1

JavaScript часто использует асинхронную парадигму, поэтому, когда вы читаете файл, например, функция, которую вы предоставляете в качестве обратного вызова, будет выполняться в собственной области. this связан с областью, поэтому вы потеряете ее. После того, как вы попытаетесь ссылаться на this.testData, на самом деле не будет ссылаться на объект DataProvider, а на объем анонимной функции, которую вы предоставили parseString.

Итак, есть несколько способов, чтобы преодолеть, и проще всего здесь будет сохраняться this в переменной в верхнем объеме, так что вы можете ссылаться на него, назовем его, например self, некоторые разработчики предпочитают that.

var DataProvider = function(dataPath) { 
    this.dataPath = dataPath; 
    this.testData; 

    var self = this; 

    fs.readFile(this.dataPath, function(err, data) { 
     var parser = new xml2js.Parser(); 
     parser.parseString(data, function(err, result) { 
      //console.log(util.inspect(result, false, null)); 
      self.testData = result; 
     }); 
    }); 
}; 

Или с помощью .bind, но dissadvantage здесь является то, что он должен быть использован дважды (как у вас есть две области для «путешествия» через:

var DataProvider = function(dataPath) { 
    this.dataPath = dataPath; 
    this.testData; 

    fs.readFile(this.dataPath, function(err, data) { 
     var parser = new xml2js.Parser(); 
     parser.parseString(data, function(err, result) { 
      //console.log(util.inspect(result, false, null)); 
      this.testData = result; 
     }.bind(this)); 
    }.bind(this)); 
}; 
+0

Спасибо. Как насчет '.bnid (это)' будет ли это работать? Это более элегантно? –

+0

Каковы другие способы преодоления? –

+0

Есть немного, '.bind' является одним из них, а также обновил ответ. – moka