如何从函数中覆盖构造函数属性



我是JavaScript编程的新手,我甚至不知道如何问Google,所以我将详细描述我想要实现的目标。

我正在使用node.js和xml2js模块为jasmine创建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>

我希望数据提供程序构造函数立即解析 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范围有关吗?

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 ,但这里的缺点是它必须使用两次(因为您有两个范围要"穿越":

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));
};

最新更新