【问题标题】:Cannot read property '-1' of undefined无法读取未定义的属性“-1”
【发布时间】:2011-06-23 16:41:44
【问题描述】:

这是我第一次尝试在 Javascript 项目中使用类 - 我正在尝试在 HTML5 Canvas 中实现 Conway 的生命游戏。 Here's the code. 如您所见,第一代渲染良好,但 next() 函数存在问题,阻止其继续运行。 (我确实注意到有问题的错误实际上是在get() 的最后一行抛出的,这是neighbors() 调用的函数之一,由next() 调用。我在这两个函数中都找不到任何问题,但显然有什么问题出错了!)

【问题讨论】:

    标签: javascript oop canvas


    【解决方案1】:

    问题是[关于% 的假设是错误的,因此]get/set 函数中的守卫没有按预期工作:

    -1 % 42 // results in -1
    

    编码愉快。


    我会考虑移除 get/set 函数中的防护,并使用 sentinel values(或其他相邻边缘套管)作为边界(例如,第一/最后一行和列实际上永远不会绘制到屏幕上)。

    这可以避免大量的警戒检查 -- get/set 每次迭代都会被调用一大堆时间(我什至不会把它们当作功能)。我认为删除 get/set 和守卫“没问题”,因为这些操作是进程内部的,并且与算法密切相关——它们没有直接暴露,JavaScript 也只有这么快。

    每个周期执行“全网格邻居检查”是C * O(h*w)。虽然它具有相同的复杂性,但明显更小的C 可以使程序运行得更快。

    【讨论】:

    • % 很奇怪,我什至在添加之前checked 那个确切的情况。感谢您的解释!
    • 我喜欢让地图边缘包裹的想法,但为了速度我可能会采用边框方法。
    • @nkorth 有很多技巧可以做。通过使用y * w + x 索引模拟二维数组,然后仅迭代数组的属性(邻居检查/更新数学也必须调整),可以将复杂性移至O(alive_cells)。或者,可以存储活细胞的[x,y](或扁平索引)列表。不过,我不确定如何获得比这更好的复杂性/性能。
    【解决方案2】:

    线

    x = x % this.width;
    

    没有按预期工作:

    -1 % 640 
    

    给予

    -1
    

    简单修复:

    x = (x + this.width) % this.width;
    

    【讨论】:

      【解决方案3】:

      让我们检查第一个单元格。假设 x 为 0,y 为 0。在处理该单元格期间,您最终将检查 this.map[-1][-1]。由于 this.map[-1] 未定义,因此即使元素 -1 确实存在(它不存在),您也无法在其中找到元素。

      你有几个选择:

      • 在抓取该单元格左侧的任何东西之前检查x > 0,并在抓取它右侧的任何东西之前检查x < this.width - 1。 y 和 this.height 的类似故事。
      • 在尝试访问其中的任何内容之前,请确保已定义 this.map[x - 1] 或 this.map[x + 1]。与y +/- 1 相同——如果它未定义,则认为它是错误的。
      • 将this.map[-1] 和this.map[whatever][-1] 定义为false,以及this.map[this.width] 和this.map[whatever][this.height]。
      • 重做数学运算,使x - 1 变为(x + width - 1) % width。与y - 1 相同。这应该使地图环绕。

      【讨论】:

        【解决方案4】:

        next 中有这个循环:

         for(var y = 0; y < this.height; y++){
             for(var x = 0; x < this.width; x++){
                 newMap[x][y] = this.get(x, y);
        
                 //Rule 1: any live cell with fewer than two live neighbors dies
                 if(this.get(x, y) == true && this.neighbors(x, y) < 2){
                     newMap[x][y] = false;
                 }
        
                 //...
        

        所以在您的第一次迭代中,x 和 y 为零。现在看看neighbors 在做什么:

        this.neighbors = function(x, y){
            n = 0;
            //...
            if(this.get(x-1, y-1)){n++;}
            //...
            return n;
        }
        

        如果x 和y 是0,它会尝试检查单元格(-1,-1):

        this.map[x][y] = val;
        

        但是您的 map 只有正整数键。

        如果您想“环绕”,请增加 get 中的值以避免负值:

        x = (x + this.width) % this.width;
        y = (y + this.height) % this.height;
        

        【讨论】:

        • 我实际上打算让它变为负数,所以我可以使用 get() 和 set() 函数中的代码在边缘制作地图循环。但是,这与问题有关(请参阅 pst 的回答)
        猜你喜欢
        • 2019-10-18
        • 1970-01-01
        • 1970-01-01
        • 2021-12-21
        • 2014-07-31
        • 1970-01-01
        • 2016-03-25
        • 1970-01-01
        • 2022-12-08
        相关资源
        最近更新 更多