Ideally, you'd structure it in whatever way would allow you to write self-describing code.
chess_board.move("Black", "Rook2", [2, 0]);
Both of these are horrible pseudocode hacks and not exactly indicative of the final product, but hopefully provide consideration of how you might want to address the abstract concepts of playing the boardgame in terms of your code.
In terms of common issues, are you planning on animating pieces as they move?
If so, you might want pieces to control their own state.
Another consideration might be to "bind" and "unbind" pieces from squares.
Give the pieces a simple, loosely-coupled interface for querying the square they're in and/or the square they're moving to.
Your board could talk 100% in grid-coordinates (making rule-keeping easier, depending on the game), then the pieces could use those grid-coordinates to enforce rules, AND to request a connection to talk to their new grid square (dropping the connection to the previous square).
Most of the positioning logic for drawing, et cetera, could be held within a piece, which just needs to take the grid-coordinates and position itself inside the center of the grid square (when it's done animating).
At this point, pieces and squares could be put in separate arrays and updated separately, even.
Pieces would control their logic/presentation based on the grid coordinates they're given by the squares they're talking to.
Squares could maintain any bonuses that they might hold (snakes/triple-word-score/go directly to jail), and confer those to a piece, if the square believes that the rule is appropriate to that piece at that time (eg: go-to-jail/jail + just-visiting).
Note that this isn't THE way to do things.
In fact, it might be way over-engineered for your needs.
Or it might just look like nonsense, because you'd really like to write the code from the perspective of the player who rolls dice/picks up a card/etc and manually moves a piece, versus a piece which moves itself or a board which pushes a piece around.