nodejs-tw / ama

Ask me anything!
MIT License
31 stars 1 forks source link

Module Cache導致inherits共用錯誤 #3

Open b60413 opened 8 years ago

b60413 commented 8 years ago

目的

最近初學node.js, 想要自己嘗試寫一個Map module讓其他module去繼承, 但是require module的cache機制導致inherits的module共用了同一個map, 請問應該如何修改才有辦法讓各module有自己的map?

使用的工具

ubuntu 12.04 node.js 4.4.3

操作流程

node server.js

遇到的問題

目的已詳述

嘗試過的解法

應該是架構問題, 完全不知道該從何處下手 (想過用不同的路徑載入Map Module, 但就捨棄了module cache的機制)

程式碼

-----server.js-----

//Load Library
var Player_list_lib = require(global.LIB_DIR + '/player_list_lib');
var Monster_list_lib = require(global.LIB_DIR + '/monster_list_lib');

//Create Monster
for (var monster_index = 1; monster_index <= 3; ++monster_index) {  
    Monster_list_lib.set(monster_index, 'a');
}

//Show Map
console.log(Monster_list_lib.keys());
console.log(Player_list_lib.keys());

-----map.js-----

/**
 * Map Library
 */
function Map_lib() {
    /**
     * Map
     */
    _map = {};

    /**
     * Map Count
     */
    this.size = 0;
}

/**
 * Get
 * @param key
 * @param default_val
 */
Map_lib.prototype.get = function(key, default_val) {
    //Initail Parameter
    default_val = default_val || undefined;

    //Check Key Exists
    if ( ! _map.hasOwnProperty(key)) {
        return default_val;
    }

    //Response Item
    return _map[key];
};

/**
 * Set
 * @param key
 * @param value
 */
Map_lib.prototype.set = function(key, value) {
    //Set Item
    _map[key] = value;

    //Increase Map Count
    ++this.size;
};

/**
 * Has
 * @param key
 * @returns {Boolean}
 */
Map_lib.prototype.has = function(key) {
    return _map.hasOwnProperty(key);
};

/**
 * Remove
 * @returns mixed
 */
Map_lib.prototype.remove = function(key) {
    //Check Map Count
    if (this.size < 1) {
        return;
    }

    //Check Key Exists
    if ( ! _map.hasOwnProperty(key)) {
        return;
    }

    //Remove
    delete _map[key];

    //Decrease Map Count
    --this.size;
};

/**
 * Get Map Size
 * @returns {Number}
 */
Map_lib.prototype.size = function() {
    return this.size;
};

/**
 * Clear Map
 */
Map_lib.prototype.clear = function() {
    //Re-initial Map
    _map = {};

    //Re-initial Map Count
    this.size = 0;
};

/**
 * Get Entries
 * @returns {Array}
 */
Map_lib.prototype.entries = function() {
    //Initial List
    var list = [];

    //Deal With Map
    this.keys().forEach(function(key) {
        list.push([key, _map[key]]);
    }, this);

    //Response List
    return list;
};

/**
 * Get Keys
 * @returns {Array}
 */
Map_lib.prototype.keys = function() {
    return Object.keys(_map);
};

/**
 * Get Values
 * @returns {Array}
 */
Map_lib.prototype.values = function() {
    //Initial List
    var list = [];

    //Deal With Map
    this.keys().forEach(function(key) {
        list.push(_map[key]);
    }, this);

    //Response List
    return list;
};

//Export
module.exports = Map_lib;

-----Player_list_lib.js / Monster_list_lib.js-----

//Load Module
var util = require('util');

//Load Library
var Map_lib = require(global.LIB_DIR + '/map_lib');

/**
 * Constructor
 */
function Player_list_lib() {
    //Parent Constructor
    Player_list_lib.super_.apply(this, arguments);
};

/**
 * Instance
 */
Player_list_lib._instance = undefined;

/**
 * Get Instance
 */
Player_list_lib.getInstance = function() {
    if (this._instance === undefined) {
        this._instance = new Player_list_lib();
    }

    return this._instance;
};

//Inherits 'List_lib'
util.inherits(Player_list_lib, Map_lib);

//Exports
module.exports = Player_list_lib.getInstance();

輸出

[ '1', '2', '3' ] [ '1', '2', '3' ]

chentsulin commented 8 years ago

require 進來的的東西是個 singleton,然後做了 prototype 繼承所以共用同一個物件

https://github.com/nodejs/node/blob/master/lib/util.js#L896:

exports.inherits = function(ctor, superCtor) {

  if (ctor === undefined || ctor === null)
    throw new TypeError('The constructor to "inherits" must not be ' +
                        'null or undefined');

  if (superCtor === undefined || superCtor === null)
    throw new TypeError('The super constructor to "inherits" must not ' +
                        'be null or undefined');

  if (superCtor.prototype === undefined)
    throw new TypeError('The super constructor to "inherits" must ' +
                        'have a prototype');

  ctor.super_ = superCtor;
  Object.setPrototypeOf(ctor.prototype, superCtor.prototype);
};

可以去了解一下 prototype 繼承跟一般 class 繼承差在哪

js 實作繼承的招數太多,有七八種以上,可參考 http://shichuan.github.io/javascript-patterns/#code-reuse-patterns

甚至用 plain object 都可以做到大部份繼承想要做到的事