(为什么)在有限的ng-repeat中有一个“调用自身”的指令会导致无限递归的堆栈溢出?

时间:2015-06-02 23:20:02

标签: javascript angularjs recursion angular-directive

编辑:有关问题的简化版本(this plunker),请参阅sscce

以下代码似乎会导致无限递归问题:

statement.directive.html

public static boolean pieceInWay(final GamePiece[][] board, final Move move) {
        final int changerx = (int) Math.signum(move.getdx());
        final int changery = (int) Math.signum(move.getdy());
        switch (Direction.getFromDelta(changerx, changery)) {
        case DOWN:
            for (int y = move.start.y + 1; y < move.end.y; y++) {
                if (board[y][move.start.x] != null) {
                    return true;
                }
            }
            break;
        case DOWN_LEFT:
            for (int y = move.start.y + 1, x = move.start.x - 1; y < move.end.y; y++, x--) {
                if (board[y][x] != null) {
                    return true;
                }
            }
            break;
        case DOWN_RIGHT:
            for (int y = move.start.y + 1, x = move.start.x + 1; y < move.end.y; y++, x++) {
                if (board[y][x] != null) {
                    return true;
                }
            }
            break;
        case LEFT:
            for (int x = move.start.x - 1; x > move.end.x; x--) {
                if (board[move.start.y][x] != null) {
                    return true;
                }
            }
            break;
        case RIGHT:
            for (int x = move.start.x + 1; x < move.end.x; x++) {
                if (board[move.start.y][x] != null) {
                    return true;
                }
            }
            break;
        case UP:
            for (int y = move.start.y - 1; y > move.end.y; y--) {
                if (board[y][move.start.x] != null) {
                    return true;
                }
            }
            break;
        case UP_LEFT:
            for (int y = move.start.y - 1, x = move.start.x - 1; y > move.end.y; y--, x--) {
                if (board[y][x] != null) {
                    return true;
                }
            }
            break;
        case UP_RIGHT:
            for (int y = move.start.y - 1, x = move.start.x + 1; y > move.end.y; y--, x++) {
                if (board[y][x] != null) {
                    return true;
                }
            }
            break;
        }
        return false;
    }

    @FunctionalInterface
    public static interface IsLegalMove {
        public boolean call(GamePiece piece, GamePiece pieceOnEndTile, GamePiece[][] board, Move move);
    }

    private static enum Direction {
        UP(0, -1),
        UP_RIGHT(1, -1),
        RIGHT(1, 0),
        DOWN_RIGHT(1, 1),
        DOWN(0, 1),
        DOWN_LEFT(-1, 1),
        LEFT(-1, 0),
        UP_LEFT(-1, -1);

        public final int dx;
        public final int dy;

        private Direction(final int dx, final int dy) {
            this.dx = dx;
            this.dy = dy;
        }

        public static Direction getFromDelta(final int dx, final int dy) {
            for (final Direction d : values()) {
                if (d.dx == dx && d.dy == dy) {
                    return d;
                }
            }
            return null;
        }
    }

我不知道为什么。 <textarea></textarea><br /> <button ng-click='statement.newStatement()'>New Statement</button> <button ng-click='statement.newSubstatement()'>New Substatement</button> <hr /> <statement ng-repeat='statement in statement.curr.sections' curr='statement' parent='statement.curr'> </statement> 为零(当我测试它时)。那么这个指令不会被“实例化/实现”吗?

statement.curr.sections

不会造成任何问题。

将其封装在<p ng-repeat='statement.curr.sections'>x</p> 并不能解决问题。

ng-if

编辑:这也不起作用(但我意识到我选择了错误的变量名称)。

<div ng-if='statement.curr.sections > 0'>
  <statement
    ng-repeat='statement in statement.curr.sections'
    curr='statement'
    parent='statement.curr'>
  </statement>
</div>

GitHub上的代码。

1 个答案:

答案 0 :(得分:1)

我看了一下你的github代码,但它确实令人困惑。命名肯定会让我的大脑陷入困境,所以我首先要澄清一下。

对于指令,您应该使用前缀,以便明确您引用指令:即。 myStatements,elStatement,等等。

对于服务和控制器,请使用后缀:StatementService,StatementController。

我不明白:

<button ng-click='statement.newStatement()'>New Statement</button>

statement.这里指的是什么?这什么时候被初始化/绑定到视图?编辑:没关系,我看到那是控制器。

好的,所以你有指令的模板,引用指令本身......

嗯,不确定指令是否可以有一个本身的子指令。当模板尝试渲染时,似乎非常无限循环。因为即使下一个图层/指令没有数据,它仍然需要引导指令及其模板,因此导致它加载下一个指令......它永远不会完成。

看起来像一个反模式。用例是什么?你想画分形吗?洛尔

就分形而言,你需要通过一个极限(即,当分形变得如此之小以至于无法看到它时,就不再需要绘制它了)。因此,通过施加一些限制,你可以阻止它无限地试图绘制。

tl; dr:即使数据为空,仍会初始化/呈现子指令。