实例化模块内部的类时超出最大调用堆栈

我的第7行console.log打印出来罚款。

host.js

"use strict"; var engine = require('./engine.js'); var base = require('./base.js'); var player = new base.Avatar(); console.log(player.x); class PillarGame extends engine.ServerGame { connectPlayer(socket) { var player = new base.Avatar(); this.add('players', player); console.log("added player"); //announce } } module.exports = {'HostedGame' : PillarGame}; 

但是,我创build该对象后,发生在我的服务器崩溃:

  if (obj.hasOwnProperty(key) && _hasBinary(obj[key])) { ^ RangeError: Maximum call stack size exceeded at Object.hasOwnProperty (native) 

为什么这个崩溃?

base.js没有要求。

堆栈跟踪:

 listening connected added player /Users/quantum/code/online/node_modules/socket.io/node_modules/has-binary-data/index.js:0 (function (exports, require, module, __filename, __dirname) { /* RangeError: Maximum call stack size exceeded at _hasBinary (/Users/quantum/code/online/node_modules/socket.io/node_modules/has-binary-data/index.js:24:22) at _hasBinary (/Users/quantum/code/online/node_modules/socket.io/node_modules/has-binary-data/index.js:37:15) at _hasBinary (/Users/quantum/code/online/node_modules/socket.io/node_modules/has-binary-data/index.js:47:40) at _hasBinary (/Users/quantum/code/online/node_modules/socket.io/node_modules/has-binary-data/index.js:47:40) at _hasBinary (/Users/quantum/code/online/node_modules/socket.io/node_modules/has-binary-data/index.js:47:40) at _hasBinary (/Users/quantum/code/online/node_modules/socket.io/node_modules/has-binary-data/index.js:37:15) at _hasBinary (/Users/quantum/code/online/node_modules/socket.io/node_modules/has-binary-data/index.js:47:40) at _hasBinary (/Users/quantum/code/online/node_modules/socket.io/node_modules/has-binary-data/index.js:47:40) at _hasBinary (/Users/quantum/code/online/node_modules/socket.io/node_modules/has-binary-data/index.js:47:40) at _hasBinary (/Users/quantum/code/online/node_modules/socket.io/node_modules/has-binary-data/index.js:37:15) 

server.js,在socket.emit("game.things", game.things);上崩溃socket.emit("game.things", game.things);

 var express = require('express'); var path = require('path'); var app = express(); var server = require('http').createServer(app); var io = require('socket.io')(server); var logic = require('./logic'); var hostedGame = require('./host'); var game = new hostedGame.HostedGame({'sockets' : io.sockets}); app.use(express.static(path.join(__dirname, 'public'))); server.listen(3000, function() { console.log('listening'); }); io.on('connection', function(socket) { console.log('connected'); //extrac game.connectPlayer(socket); //console.log("game.things['players']" + game.things['players']);; socket.emit("game.things", game.things); // socket.on('input', function(data) { // game.input(socket, data); // }); }); var loopAsync = function() { setTimeout(loop, 10); //setImmediate(loop); } var now = Date.now(); var last = now; var dt = 0.00; var rate = 10; function loop() { now = Date.now(); var delta = now - last; last = now; dt = dt + delta; if (dt < rate) { loopAsync(); return; } else { dt -= rate; //if dt still > rate, repeat the following while true var updates = game.loop(); //emit things io.sockets.emit('player-positions', logic.players); //io.to specific player loopAsync(); } } loopAsync(); 

base.js

 "use strict"; class Component { defaultMaxCharge() { return [0]; } constructor(options) { options = options || {}; this.charge = [0]; if (options['maxCharge']) { this.maxCharge = options['maxCharge']; } else { this.maxCharge = this.defaultMaxCharge(); } } loop() { } getValue(name, hash) { return hash; } } class Looper extends Component { registrationNames() { return ['loop']; } } class Mover extends Looper { loop() { var velocity = this.thing.getValue('velocity'); var speed = this.thing.getValue('speed')['speed']; var total = Math.abs(velocity.vx) + Math.abs(velocity.vy); if (total <= 0) { return; } var xx = velocity.mx / total * this.speedMod(); var yy = velocity.my / total * this.speedMod(); this.thing.x = this.thing.x + xx * speed; this.thing.y = this.thing.y + yy * speed; this.thing.x += velocity.vx; this.thing.y += velocity.vy; //announce } } //input components class XWalker extends Component { constructor(options) { super(options); this.vx = 0; } registrationNames() { return ['input', 'velocity']; } getValue(name, hash) { if (name == 'velocity') { hash.vx = this.vx; //times speed } return hash; } processEvent(name, eventer, hash) { if (name == 'input') { if (hash.left) { this.vx = -1; } else if (hash.right) { this.vx = 1; } else { this.vx = 0; } } } } class YWalker extends Component { constructor(options) { super(options); this.vx = 0; } registrationNames() { return ['input', 'velocity']; } getValue(name, hash) { if (name == 'velocity') { hash.vy = this.vy; //times speed } return hash; } processEvent(name, eventer, hash) { if (name == 'input') { if (hash.up) { this.vy = -1; } else if (hash.down) { this.vy = 1; } else { this.vy = 0; } } } } class Thing { spawnComponents(options) { return []; } installComponents(options) { this.componentRegistrations = {}; this.components = []; var comps = this.spawnComponents(options); for (var i = 0; i < comps.length; i++) { var component = comps[i]; component.thing = this; this.registerComponent(component); this.components.push(component); } } registerComponent(component) { for (var i = 0; i < component.registrationNames().length; i++) { var eventName = component.registrationNames()[i]; if (!this.componentRegistrations[eventName]) { this.componentRegistrations[eventName] = []; } this.componentRegistrations[eventName].push(component); } } getValue(name) { var registered = this.componentRegistrations[name]; if (registered) { var valueHash = {}; for (var i = 0; i < registered.length; i++) { var component = registered[i]; valueHash = component.getValue(name, valueHash); if (valueHash.stop) { return valueHash; } } return valueHash; } } processEvent(name, eventer, hash) { var registered = this.componentRegistrations[name]; if (registered) { for (var i = 0; i < registered.length; i++) { var component = registered[i]; component.processEvent(name, eventer, hash); } } } constructor(options) { if (options && options['position']) { this.x = options['position'].x * this.canvas.width; this.y = options['position'].y * this.canvas.height; } else { this.x = 2.0; this.y = 2.0; } this.installComponents(options); this.active = true; } loop() { for (var i = 0; i < this.components.length; i++) { var component = this.components[i]; component.loop(); } } afterLoop() { } position() { return {'x' : this.x, 'y' : this.y}; } } class Avatar extends Thing { spawnComponents(options) { return [new Mover(), new XWalker(), new YWalker()]; } } module.exports = {'Component' : Component, 'Thing' : Thing, 'Mover' : Mover, 'Looper' : Looper, 'XWalker' : XWalker, 'YWalker' : YWalker, 'Avatar' : Avatar}; 

 server.js, crashes on socket.emit("game.things", game.things); 

最有可能的是, game.things是一个带有循环引用的复杂对象,socket.io试图在释放之前将其转换为JSON,并且失败。