在javascript中实例化循环中的类使用最后一个值

首先,我知道
JavaScript中有很多关于闭包的问题,​​特别是涉及循环时.我已经阅读了很多,但我似乎无法弄清楚如何解决我自己的特定问题.我的主要经验在于C#,C和一些ASM,并且它已经习惯了JavaScript.

我试图在一些for循环中用一个类的新实例(称为Tile)填充一个三维数组.我想要做的就是将一个其他类(称为Group)的引用传递给第一个循环中实例化的(并且还添加到另一个数组中).正如您可能已经猜到的,在完成循环之后,Tile类的每个实例都引用了同一个Group对象,即最后一个要创建的对象.

显然,不是传递对Group对象的引用,而是传递对函数本地的某个变量的引用,该引用在循环的每次迭代中都会更新.我的假设是解决这个问题与闭包有关,因为我在寻找解决方案时遇到了许多类似的问题.

我发布了一些修剪过的代码,在jsFiddle上公开了问题的核心:

//GW2 namespace
(function( GW2, $, undefined ) {

    //GW2Tile class
    GW2.Tile = function(globalSettings, kineticGroup)
    {
        //Private vars
        var tilegroup = kineticGroup;
//      console.log(tilegroup.grrr); //Shows the correct value
        var settings = globalSettings;

        this.Test = function(){
            console.log(tilegroup.grrr);
        }

        this.Test2 = function(group){
            console.log(group.grrr);
        }

    } //Class

}( window.GW2 = window.GW2 || {}, jQuery ));


var zoomGroups = [];
var tiles = [];
var settings = {};

InitArrays();
tiles[0,0,0].Test(); //What I want to work, should give 0
tiles[0,0,0].Test2(zoomGroups[0]); //How I'd work around the issue

function InitArrays(){
    var i, j, k, zoomMultiplier, tile;

    for(i = 0; i <= 2; i++){
        zoomGroups[i] = {};
        zoomGroups[i].grrr = i;

        tiles[i] = [];
        zoomMultiplier = Math.pow(2, i);
        for(j = 0; j < zoomMultiplier; j++){
            tiles[i,j] = [];
            for(k = 0; k < zoomMultiplier; k++){
                tile = new GW2.Tile(settings, zoomGroups[i]);
                tiles[i,j,k] = tile;
            }
        }
    }
}               

到目前为止,在使用JavaScript时,我一般都会对代码进行调整以使其工作,但我已经厌倦了使用看似凌乱的解决方法,因为我知道应该有一些相当简单的解决方案.我只是不喜欢寻求帮助,但这真的是我的头脑.任何帮助都非常感激.

最佳答案 多维数组

问题

上面代码的第一个问题是您尝试创建多维数组的方式.

您使用的语法是:

tiles[0,0,0]

但是,JavaScript将解释这一点的方式是:

tiles[0]

访问多维数组

如果您想访问multidim阵列,您必须使用:

tiles[0][0][0]

要创建multidim数组,您需要执行以下操作:

tiles = [];
tiles[0] = [];
tiles[0][0] = [];
tiles[0][0][0] = 'value';

要么:

tiles = [[['value']]];

关于你的代码

在您的代码中,您应该使用:

tiles[i][j][k] = tile;

但是在设置它的值之前,你还应该确保每个子数组实际存在,否则你将得到未定义或非法的偏移错误.

您可以通过以下方式执行此操作:

(typeof tiles[i] === 'undefined') && (tiles[i] = []);
(typeof tiles[i][j] === 'undefined') && (tiles[i][j] = []);
tiles[i][j][k] = tile;

显然,上面的内容可以根据你遍历循环的方式进行优化,最好是确保tile [i]级别在进入[j]循环之前作为数组存在,然后不用担心检查它踩着j时再次存在.

其他选择

根据您的数据集的内容,或者至少您希望使用tile数组,您可以考虑使用对象:

/// set up
tiles = {};

/// assignment
tiles[i+','+j+','+k] = 'value';

然而,这种方法可能会慢一些,尽管我的假设和不同的JavaScript解释器已多次证明我的错误.这可能是jsPerf将是你的朋友.

优化

使用tiles [i] [j] [k]方法的一个好处是它为您提供了优化引用的机会.例如,如果您要在多维数组的一个级别处理许多操作,则应执行以下操作:

/// set up
var ij = tiles[i][j];

/// use in loops or elsewhere
ij[k] = 'value'

如果您不止一次访问同一级别,这只会带来好处.

点赞