【问题标题】:Function is undefined after module.export-ing from another filemodule.export-ing 从另一个文件后函数未定义
【发布时间】:2017-03-02 08:42:56
【问题描述】:

我有一个需要 player.js 的 nodeJS 应用程序。在player.js 中我定义了Player 并添加了Player.updatePacket 方法,但是当我在main.js 中需要它并创建一个播放器实例时,player.updatePacket 是未定义的。

player.js:

module.exports.PLAYER_LIST = {};
var Player = exports.Player = {}

//constructor
Player.create = function(id) {
    var tmp = {
        id: id,
        x: 0,
        y: 0
    };
    PLAYER_LIST[id] = tmp;
    return tmp;
}

Player.updatePacket = function() {
    return {
        id: this.id,
        x: this.x,
        y: this.y
    }
}

main.js:

var Player = require('./player.js')

//get called by socket.io when a client connects
//didn't include socket.io setup in example for brevity, but this function
//is called as expected.    
io.sockets.on('connection', function(socket){
    var player = new Player(socket.id)

});

setInterval(function() {
    var dataArr = [];
    for(var i in Player.PLAYER_LIST) {
        var player = Player.PLAYER_LIST[i];
        console.log(player); //this logs: [Function]
        dataArr += player.updatePacket(); //throws TypeError: not a function
    }
    broadcast("update", dataArr);
}, 1000/25);

我尝试将导出语句移动到player.js 的底部并将updatePacket: function() {/*function contents*/} 放入tmp 对象中,但我仍然得到同样的错误。任何帮助或解释表示赞赏。

【问题讨论】:

  • 还有一个错误是你不能在一个对象上 +=。即,您的 dataArr 是一个对象,而不是一个数组。另外,PLAYER_LIST 在哪里?
  • 更新 OP 以显示 PLAYER_LIST 并将 dataArr 更改为实际数组

标签: javascript node.js


【解决方案1】:

试试这个

播放器.js

var PlayerList = module.exports.PLAYER_LIST = {};
var Player = module.exports.Player = function(id) {
  this.id = id;
  this.x = 0;
  this.y =  0
  PlayerList[id] = this;
};

Player.prototype.updatePacket = function() {
    return {
        id: this.id,
        x: this.x,
        y: this.y
    }
};

Main.js

var Player = require('./player.js').Player;
var PLAYER_LIST = require('./player.js').PLAYER_LIST;

io.sockets.on('connection', function(socket){
    var player = new Player(socket.id)

});

setInterval(function() {
    var dataArr = [];
    for(var i in PLAYER_LIST) {
        var player = PLAYER_LIST[i];
        console.log(player);
        dataArr.push(player.updatePacket()); //note that it is push not += when adding items to an array
    }
    broadcast("update", dataArr);
}, 1000/25);

这种解释可能过于简单,但在 JS 中,“类”是函数,为了给类添加方法,我们必须将它们添加到原型中。当我们在该类上使用“new”时,它会继承其原型链上存在的所有方法。

这个链接可能被证明是一个更好的解释 https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype

【讨论】:

  • Player.prototype 未定义,因此 Player.prototype.updatePacket 会引发错误。我将尝试使用 ES6 类语法重新实现它,但这种解释仍然很有帮助。
  • 感谢编辑,事实证明,从构造函数返回另一个对象会对原型链接造成严重破坏。 jsfiddle.net/g6pL9kkt
【解决方案2】:

您的模块的导出是一个具有.Player 属性的对象:

var Player = exports.Player = {};
//           ^^^^^^^^^^^^^^^^

因此,您需要在需要 Player 对象时访问该属性:

/* main.js */
var Player = require('./player.js').Player;
//                                 ^^^^^^^

(首选)替代方法是将Player 设为导出对象本身(“别名”):

/* player.js */
var Player = exports; // or = module.exports;

如果您想使用默认对象以外的其他对象,则不能使用exports,而必须使用assign to module.exports

【讨论】:

  • 我进行了首选更改,但仍然遇到相同的错误。奇怪的是错误在var player = new Player(id) 线上随机更改为TypeError: Player is not a constructor。只需运行相同的代码大约五次就会随机产生两个错误
  • 鉴于您异步执行函数,这可能是一种竞争条件,无论哪个先发生都会得到异常。但是,是的,两者似乎都是错误的。 Player 不是构造函数 - 要么你想让它成为一个类,要么你想调用 Player.create 而不是 new Player,并且 updatePacket 被写成 Player 上的静态方法@ 不是播放器上的方法对象。您可以使用Player.updatePacket.call(player),但我真的认为您正在寻找class 构造。
  • 谢谢你澄清了很多。我使用的是 ES6 之前的类语法,因为我发现大多数示例都是这样编写的。如何使 updatePacket 成为 Player 上的实例方法,还是只有类才有可能?
  • @BrianJ 请参阅 derp 的答案(这里不会在 cmets 中重复:D)您将使用构造函数及其 .prototype 对象
猜你喜欢
  • 1970-01-01
  • 2019-09-29
  • 1970-01-01
  • 2017-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-08
相关资源
最近更新 更多