浅物体的克隆? - Javascript

时间:2016-02-15 11:36:11

标签: javascript oop clone

我的项目object有一个核心SudokuBoard。唯一的字段SudokuBoard2D arraySudokuBoard的所有原型函数都涉及2D array,并且需要始终对其进行可见性。

问题:

在即将出现的算法中,我 NEED 可以通过某种方式制作SudokuBoard的副本。这是强制性的功能。 每当我尝试制作副本时,它的2D数组只是对旧数组的引用。我不知道为什么。

我在clone读到Javascript绝对是一场噩梦,所以我有点担心。我是初学者,所以我要做的最后一件事是安装Jquery或使用一些外部库来解决这个问题。我提供了以下文件;他们应该没有错误地运行。

SudokuBoard.js

/**
 * Constructs a SudokuBoard object.
 * Initializes the board with the numbers
 * provided to the constructor.
 * @param nums array, must be BOARD_SIZE^2 length.
 * @constructor
 */

function SudokuBoard(nums)
{
    // Private Fields:

    var BOARD_SIZE = 9;
    // The Sudoku board, represented as a 2D array.
    var gameboard = [];

    if (nums.length != BOARD_SIZE * BOARD_SIZE)
    {
        document.write("InvalidSizeError");
        throw "InvalidSizeError";
    }

    var counter = 0;
    for (var i = 0; i < BOARD_SIZE; i++)
    {
        var row = [];

        // Each row has a set amount of elements.
        while (row.length < BOARD_SIZE)
        {
            row.push(nums[counter]);
            counter++;
        }

        // Add the row to the board.
        gameboard.push(row);
    }

    SudokuBoard.prototype.getBoard = function()
    {
        return gameboard;
    }
}

/**
 * Gets all values within a row of the 2D array.
 * The Y coordinate works on the typical number
 * scale, meaning indexes start from 1, not 0.
 * Y corresponds to the vertical axis. The bottom
 * left of the board is at 1,1. The bottom right
 * of the board is at 9,1.
 * @param y coordinate of the row.
 * @returns {Array}
 */
SudokuBoard.prototype.getRow = function(y)
{
    return this.getBoard()[this.getBoard().length - y];
};

/**
 * Gets all values within a column of the 2D array.
 * The X coordinate works on the typical number
 * scale, meaning indexes start from 1, not 0.
 * X corresponds to the horizontal axis. The bottom
 * left of the board is at 1,1. The bottom right
 * of the board is at 9,1.
 * @param x coordinate of the column.
 * @returns {Array}
 */
SudokuBoard.prototype.getColumn = function(x)
{
    var column = [];

    for (var i = 1; i <= this.getBoard().length; i++)
    {
        column.push(this.getSlot(x, i));
    }

    return column;
};

/**
 * Algorithm which finds the correct quadrant of a given
 * coordinate and gets all the numbers which are contained
 * inside it. This operation relies on the fact that there
 * are three quadrants and once you make it so the first
 * index of quadrant one is considered as (3,3) you can
 * divide all X and Y values by 3 and yield their quadrant #.
 * @param x coordinate.
 * @param y coordinate.
 * @returns {Array}
 */
SudokuBoard.prototype.getQuadrant = function(x, y)
{
    // Determine what quadrant this coordinate is in.
    var horizQuad = Math.floor((x + 2) / 3); // 1 2 or 3
    var vertQuad = Math.floor((y + 2) / 3); // 1 2 or 3

    var quadrant = [];

    for (var i = 1; i <= 3; i++)
    {
        for (var h = 1; h <= 3; h++)
        {
            // Add the number to the array.
            quadrant.push(this.getSlot((horizQuad - 1) * 3 + i, (vertQuad - 1) * 3 + h));
        }
    }

    return quadrant;
};

/**
 * Gets a given slot on the board.
 * The X,Y coordinates work on the typical number
 * scale, meaning indexes start from 1, not 0.
 * X corresponds to the horizontal axis while Y
 * corresponds to the vertical axis. The bottom
 * left of the board is at 1,1. The bottom right
 * of the board is at 9,1.
 * @param x coordinate.
 * @param y coordinate.
 */
SudokuBoard.prototype.getSlot = function(x, y)
{
    return this.getBoard()[this.getBoard().length - y][x - 1];
};

/**
 * Sets a given slot on the board to a value.
 * The X,Y coordinates work on the typical number
 * scale, meaning indexes start from 1, not 0.
 * X corresponds to the horizontal axis while Y
 * corresponds to the vertical axis. The bottom
 * left of the board is at 1,1. The bottom right
 * of the board is at 9,1.
 * @param x coordinate.
 * @param y coordinate.
 * @param value to be placed.
 */
SudokuBoard.prototype.setSlot = function(x, y, value)
{
    this.getBoard()[this.getBoard().length - y][x - 1] = value;
};

SudokuBoard.prototype.clone = function()
{
    var numbers = [];

    for (var i = 0; i < this.getBoard().length; i++)
    {
        for (var h = 0; h < this.getBoard()[i].length; h++)
        {
            numbers.push(this.getBoard()[i][h]);
        }
    }

    return new SudokuBoard(numbers);
};

/**
 * ToString() method for SudokuBoard.
 * @returns {string}
 */
SudokuBoard.prototype.toString = function()
{
    const border = "+-----+-----+-----+";
    const nextline = "<br>";

    var temp = border + nextline;

    for (var i = 0; i < this.getBoard().length; i++)
    {
        temp += "|";

        for (var h = 0; h < this.getBoard()[i].length; h++)
        {
            // Every third character is proceeded by a |
            //\u00A0 for empty space.
            temp += ((this.getBoard()[i][h] == "0") ? "-" : this.getBoard()[i][h]) + ((h % 3 == 2) ? "|" : " ");
        }

        // Add a new line.
        temp += nextline;
    }

    // Return and add the bottom border.
    return temp + border;
};

Tester.js

var nums = [0, 0, 0, 0, 0, 0, 1, 4, 6,
            4, 0, 8, 7, 0, 0, 0, 0, 0,
            0, 6, 0, 0, 5, 0, 8, 9, 0,
            0, 0, 0, 1, 0, 0, 0, 0, 3,
            0, 8, 0, 0, 7, 4, 0, 0, 0,
            7, 0, 0, 0, 0, 0, 9, 0, 0,
            0, 0, 1, 8, 0, 9, 2, 0, 0,
            0, 0, 0, 5, 0, 0, 0, 0, 0,
            8, 0, 3, 0, 1, 7, 0, 0, 0];

var myBoard = new SudokuBoard(nums);
println("ORIGINAL:");
println(myBoard);

var clone = myBoard.clone();
println("CLONING:");
println(clone);

myBoard.setSlot(1, 1, 3);
println("CHANGED ORIGINAL:");
println(myBoard);

println("CLONE:");
println(clone);




/**
 * Used for debugging.
 * @param line
 */
function println(line)
{
    document.write(line + "<br>");
}

Runner.html

    <!DOCTYPE html>
<!--
  Project: SudokuSolver
  Name: Kevin
  Date: 2/12/2016
 -->

<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <font face="monospace"><font size="12">
    <!--Load from JavaScript file. -->
    <script type="text/javascript" src="SudokuBoard.js"></script>
    <script type="text/javascript" src="Tester.js"></script>
    </font></font>
</head>
<body>

</body>
</html>

3 个答案:

答案 0 :(得分:3)

我发现你的.clone()方法没有任何问题。

问题出在你的构造函数中,它是如何设置.getBoard()方法的。每次调用构造函数时都会覆盖 prototype .getBoard()方法,并且该方法引用闭包捕获的局部变量,而不是实例变量。所以为任何的SudokuBoard实例调用.getBoard(),你得到的原型方法将引用最新实例的闭包中的局部变量,因此只返回最近创建的板。

更改此行:

SudokuBoard.prototype.getBoard = function()

创建实例方法而不是原型方法:

this.getBoard = function()

如果每个实例都有自己的.getBoard(),那么它们都会引用它们自己的闭包。

答案 1 :(得分:0)

基元按值传递,对象通过“引用副本”传递。

这是我的导师让我克隆JavaScript对象的片段:

function cloneObj(obj) {
    var result = {};
    for(var key in obj) {
        if (obj.hasOwnProperty(key)) {
            if (typeof obj[key] == 'object') {
                result[key] = cloneObj(obj[key]);
            } else {
                result[key] = obj[key];
            }
        }
    }
    return result;
};

-

或者尝试这个(from this post)?

// Shallow copy
var newObject = jQuery.extend({}, oldObject);

// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);

答案 2 :(得分:0)

尝试David Flanagan的延伸。

{{1}}