簡體   English   中英

使用node.js正確的模塊組織

[英]correct module organization with node.js

我用普通的JavaScript構建了一個小型國際象棋游戲,為了處理導入,我將它們全部推送到html文件中,並提供了以下內容:

game.html

.
.
<body id="body">
    <script src="scripts/utils.js"></script>
    <script src="scripts/pieces.js"></script>
    .
    .
    .
    <script src="scripts/game.js"></script>
</body>
</html>

現在,我開始使用Node.js,並希望移動邏輯服務器端並使用導入對其進行適當的結構化,但是我遇到了兩個問題。 第一個是

utils.js

function getEnemy(player) {
    return player===WHITE? BLACK : WHITE;
}

/**
 * A generator to generate pieces from given fen and return them all in an array.
 */
function generatePieces(fen) {

    var piece_array = [];
    var ranks = fen.split(' ')[0].split('/');
    for (var i=0; i < ranks.length; i++) {

        var squares = ranks[i];
        var rank = 8 - i;
        var file = 1; // keeping track of the current file.
        for (var j=0; j < squares.length; j++) {
            if (Number(squares[j])) {
                file += Number(squares[j]);
                continue;
            }
            var color = (squares[j] === squares[j].toUpperCase()? WHITE : BLACK);
            piece_array.push( generatePiece(squares[j], color, file, rank));
            file +=1;
        }
    }
    return piece_array;
}
function generatePiece(type, color, file, rank) {

    var square = new Square(file, rank);
    type = type.toUpperCase();
    switch(type) {
        case PAWN:
            return new Pawn(square, color);
        case KNIGHT:
            return new Knight(square, color);
        case KING:
            return new King(square, color);
        case BISHOP:
            return new Bishop(square, color);
        case ROOK:
            return new Rook(square, color);
        case QUEEN:
            return new Queen(square, color);
    }
}

/**
 * generates a square from the first two numbers in an array.
 * no validations are made.
 * @param position_array an array whose first two elements are numbers.
 * @returns {Square} a square with file equal to the first element and rank the second.
 */
function getSquareFromArray(position_array) {
    return new Square(position_array[0], position_array[1]);
}

/******* Square class
 * square object to encapsulate all these ugly arrays.
 * @param file file of the new square.
 * @param rank rank of the new square.
 */
function Square(file, rank) {
    this.file = file;
    this.rank = rank;

    /**
     * Checks if two squares have the same file and rank.
     * @param other another square
     * @returns {boolean} true if both squares are of the same position on the board.
     */
    this.equals = function(other) {
       return (this.file === other.file && this.rank === other.rank);
    };

    /**
     * Returns a string version of the square, formatted as "file rank".
     * @returns {string} string version of the square.
     */
    this.toString = function() {
        return String(file) + ' ' + String(rank);
    };


    /**
     * returns a new square with the given file and rank added to this square's file and rank.
     * @param file file to move the square
     * @param rank rank to move the square
     * @returns {Square}
     */
    this.getSquareAtOffset = function(file, rank) {
        file = Number(file)? file : 0;
        rank = Number(rank)? rank : 0;
        return new Square(this.file + file, this.rank + rank);
    };
}

/**
 * creates a new square object from a string of format '%d $d'
 * @param string string in format '%d %d'
 * returns square object
 */
function getSquareFromKey(string) {
    values = string.split(' ');
    return new Square(Number(values[0]), Number(values[1]));
}
/******* Move object
 * Move object to encapsulate a single game move.
 * Might be a bit of an overkill, but I prefer an array of moves over an array of arrays of squares.
 * @param from A square to move from.
 * @param to A square to move to.
 */
function Move(from, to) {
    this.from = from;
    this.to = to;
}

/******* SpecialMove object
 * Move object to encapsulate a single game move.
 * Might be a bit of an overkill, but I prefer an array of moves over an array of arrays of squares.
 * @param moves array of moves to make
 * @param removes array of squares to remove pieces from
 * @param insertions array of triplets, square to insert, wanted piece type, and piece color.
 */
function SpecialMove(moves, removes, insertions) {
    this.moves = moves? moves : [];
    this.removes = removes? removes : [];
    this.insertions = insertions? insertions : [];
}

我不確定如何正確導出。 如果我將每個函數/對象分別添加到module.exports中,則使用該模塊為我的每個對象(幾乎是其他任何對象),我都需要這樣做this.utils = require('./utils'); 然后調用例如square = new this.utils.Square(file, rank); ,這似乎並不是解決方案的全部優點。 有沒有更好的方法可以在全球范圍內導入此文件?

第二個是不同類型碎片的對象列表pieces.js

var WHITE = 'w';
var BLACK = 'b';

var PAWN = 'P';
var KNIGHT = 'N';
var KING = 'K';
var BISHOP = 'B';
var ROOK = 'R';
var QUEEN = 'Q';

/********* Piece class
 * The parent class of all piece types.
 * @param square square of the piece.
 * @param color color of the piece, should be either 'white' or 'black'.
 * @constructor
 */
function Piece(square, color) {
    this.square = square;
    this.color = color;
}

/**
 * Returns the path the piece needs in order to get to the given square, if it's not a capture.
 * Returns null if the piece can't reach the square in one move.
 * @param to target square.
 */

Piece.prototype.getPath = function(to) {
    return null;
};

/**
 * Returns the path the piece needs in order to capture in the given square.
 * Returns null if the piece can't reach the square in one move.
 * Implement this if the piece captures in a different way then moving (i.e. a pawn);
 * @param to target square.
 */

Piece.prototype.getCapturePath = function(to) {
    return this.getPath(to);
};

/**
 * Compares the square of the piece with given square
 * @returns {boolean} if the piece is at the given square.
 */

Piece.prototype.isAt= function(square) {
  return (this.square.equals(square));
};

/******* Pawn class
 * Holds the movement of the pawn, refer to Piece for explanations.
 * @type {Piece}
 */
Pawn.prototype = Object.create(Piece.prototype);
Pawn.prototype.constructor = Pawn;
function Pawn(square, color) {
    Piece.call(this, square, color);
    this.startPosition = (color === WHITE? 2 : 7);
    this.direction = (color === WHITE? 1 : -1);

    this.type = PAWN;
}

.
.
.

/******* Knight class
 * Holds the movement of the Knight, refer to Piece for explanations.
 * @type {Piece}
 */
Knight.prototype = Object.create(Piece.prototype);
Knight.prototype.constructor = Knight;
function Knight(square, color) {
    Piece.call(this, square, color);

    this.type = KNIGHT;
} 
.
.
.
/******* King class
 * Holds the movement of the King, refer to Piece for explanations.
 * @type {Piece}
 */
King.prototype = Object.create(Piece.prototype);
King.prototype.constructor = King;
function King(square, color, has_moved) {
    Piece.call(this, square, color);

    this.type = KING;
}
.
.
.

我不確定如何正確導入所有其他“類”以在其他地方使用。 我以為可以從util.js中將generatePiece函數module.export該文件的module.export ,從而將其轉變為一種“生成器”。 這是一個好主意嗎?

不幸的是,在node.js中似乎沒有實際的處理方法,我將嘗試給出一些通用的解決方案:

我認為可以從util.js中將generatePiece函數制作為該文件的module.export,從而將其轉變為一種“生成器”。 這是一個好主意嗎?

我認為將模塊用作獨立的utils是一個非常簡單明了的解決方案。 它易於進行單元測試,並在node.js項目中不斷使用。

如果我將每個函數/對象分別添加到module.exports中,則使用該模塊為我的每個對象(幾乎是任何其他對象),我都需要這樣做。utils = require('./ utils') ; 然后調用例如square = new this.utils.Square(file,rank);,這似乎並不是解決方案的全部優點。 有沒有更好的方法可以在全球范圍內導入此文件?

除了可以將require d庫作為屬性存儲在對象中之外,您還可以通過常用的全局引用構造新的正方形:

utils = require('./utils'); and then call, for example, utils = require('./utils'); and then call, for example, square = new utils.Square(file,rank);`

甚至可以進一步細分您的模塊,甚至可以創建部件模塊或板模塊。

我嘗試創建盡可能多的模塊。 好處之一是節點中有很多庫可以模擬require 如果您最終要進行IO,那么對單元測試進行模擬可能很重要。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM