Create a copy of a module instead of an instance i

2019-08-09 03:21发布

问题:

this would be my first question ever on stackoverflow, hope this goes well. I've been working on a game (using corona SDK) and I used Node.js to write a small little server to handle some chat messages between my clients, no problems there. Now I'm working on expanding this little server to do some more, and what I was thinking to do is create an external file (module) that will hold an object that has all the functions and variables I would need to represent a Room in my games "Lobby", where 2 people can go into to play one against the other, and each time I have 2 players ready to play, I would create a copy of this empty room for them, and then initialize the game in that room. So I have an array in my main project file, where each cell is a room, and my plan was to import my module into that array, and then I can init the game in that specific "room", the players would play, the game will go on, and all would be well... but... my code in main.js:

var new_game_obj = require('./room.js');

games[room_id] = new_game_obj();

games[room_id].users = [user1_name,user2_name];

Now, in my room.js, I have something of the sort:

var game_logistics = {};

game_logistics.users = new Array();

game_logistics.return_users_count = function(){
    return game_logistics.users.length;
}

module.exports = function() {
    return game_logistics;
}

So far so good, and this work just fine, I can simply go:

games[room_id].return_users_count()

And I will get 0, or 1, or 2, depending of course how many users have joined this room. The problems starts once I open a new room, since Node.js will instance the module I've created and not make a copy of it, if I now create a new room, even if I eliminated and/or deleted the old room, it will have all information from the old room which I've already updated, and not a new clean room. Example:

var new_game_obj = require('./room.js');

games["room_1"] = new_game_obj();
games["room_2"] = new_game_obj();

games["room_1"].users = ["yuval","lahav"];

_log(games["room_1"].return_user_count()); //outputs 2...
_log(games["room_2"].return_user_count()); //outputs 2...

Even doing this:

var new_game_obj = require('./room.js');
games["room_1"] = new_game_obj();

var new_game_obj2 = require('./room.js');
games["room_2"] = new_game_obj2();

games["room_1"].users = ["yuval","lahav"];

_log(games["room_1"].return_user_count()); //outputs 2...
_log(games["room_2"].return_user_count()); //outputs 2...

Gives the same result, it is all the same instance of the same module in all the "copies" I make of it. So my question as simple as that, how do I create a "clean" copy of my original module instead of just instancing it over and over again and actually have just one messy room in the end?

回答1:

What you're doing is this (replacing your require() call with what gets returned);

var new_game_obj = function() {
    return game_logistics;
}

So, every time you call new_game_obj, you return the same instance of game_logistics.

Instead, you need to make new_game_obj return a new instance of game_logistics;

// room.js
function Game_Logistics() {
    this.users = [];

    this.return_users_count = function(){
        return this.users.length;
    };
}

module.exports = function() {
    return new Game_Logistics(); 
}

This is quite a shift in mentality. You'll see that we're using new on Game_Logistics in module.exports to return a new instance of Game_Logistics each time it's called.

You'll also see that inside Game_Logistics, this is being used everywhere rather than Game_Logistics; this is to make sure we're referencing the correct instance of Game_Logistics rather than the constructor function.

I've also capitalized your game_logistics function to adhere to the widely-followed naming convention that constructor functions should be capitalized (more info).

Taking advantage of the prototype chain in JavaScript is recommended when you're working with multiple instances of functions. You can peruse various articles on "javascript prototypical inheritance* (e.g. this one), but for now, the above will accomplish what you need.