> return this.prop + elt;
> }, this); // ← без bind
> }
>};
>console.log(test.addPropTo([5]));
>// → [15]
Это работает только с теми функциями высшего порядка, у которых есть такой контекстный параметр. Если нет – приходится использовать другие упомянутые подходы.
В нашей собственной функции высшего порядка мы можем включить поддержку контекстного параметра, используя метод >call
для вызова функции, переданной в качестве аргумента. К примеру, вот вам метод >forEach
для нашего типа >Grid
, вызывающий заданную функцию для каждого элемента сетки, который не равен >null
или >undefined
:
>Grid.prototype.forEach = function(f, context) {
> for (var y = 0; y < this.height; y++) {
> for (var x = 0; x < this.width; x++) {
> var value = this.space[x + y * this.width];
> if (value != null)
> f.call(context, value, new Vector(x, y));
> }
> }
>};
Следующий шаг – создание метода >turn
(ход) для мирового объекта, дающего существам возможность действовать. Он будет обходить сетку методом >forEach
, и искать объекты, у которых есть метод >act
. Найдя объект, >turn
вызывает этот метод, получая объект >action
и производит это действие, если оно допустимо. Пока мы понимаем только действие >“move”
.
Есть одна возможная проблема. Догадаетесь, какая? Если мы позволим существам двигаться по мере того, как мы их перебираем, они могут перейти на клетку, которую мы ещё не обработали, и тогда мы позволим им сдвинуться ещё раз, когда очередь дойдёт до этой клетки. Таким образом, нам надо хранить массив существ, которые уже сделали свой шаг, и игнорировать их при повторном проходе.
>World.prototype.turn = function() {
> var acted = [];
> this.grid.forEach(function(critter, vector) {
> if (critter.act && acted.indexOf(critter) == -1) {
> acted.push(critter);
> this.letAct(critter, vector);
> }
> }, this);
>};
Второй параметр метода >forEach
используется для доступа к правильной переменной >this
во внутренней функции. Метод >letAct
содержит логику, которая позволяет существам двигаться.
>World.prototype.letAct = function(critter, vector) {
> var action = critter.act(new View(this, vector));
> if (action && action.type == "move") {
> var dest = this.checkDestination(action, vector);
> if (dest && this.grid.get(dest) == null) {
> this.grid.set(vector, null);
> this.grid.set(dest, critter);
> }
> }
>};
>World.prototype.checkDestination = function(action, vector) {
> if (directions.hasOwnProperty(action.direction)) {
> var dest = vector.plus(directions[action.direction]);
> if (this.grid.isInside(dest))