Ссылка на этот элемент вне цикла for в JavaScript (JSLint)

Заранее спасибо за вашу помощь!

Я создаю простую игру в крестики-нолики, которая поможет мне изучить нативный JavaScript, поэтому моя цель - сделать как можно больше без jQuery или HTML/CSS для игры.

Я использую for-loop создать несколько div элементы, придерживаясь JSLint. Я прилагаю .addEventListener() как часть процесса создания моего div элементы для изменения цвета фона этого конкретного div при нажатии.

Я искал Stackru, пытаясь использовать this ссылаться на конкретный div щелкнул. Пока я добился успеха только с помощью анонимной функции в моем for-loop, JSLint не впечатлен, и я получаю:

Не создавайте функции внутри цикла.

Когда я пытаюсь вызвать внешнюю функцию и передать this в целом div процесс создания просто перестает работать, и я не уверен, почему.

Что у меня есть (это "работает"): https://jsfiddle.net/typj2LLb/4/

// create game
var gameContainer = document.getElementById('board');
var createBoard = function() {
  'use strict';
  var index, square;
  for (index = 0; index < 9; index += 1) {
    square = document.createElement('div');
    square.className = 'tile';

    // tile event
    square.addEventListener('click', function() {
      this.style.backgroundColor = 'yellow';
    });

    gameContainer.appendChild(square);
  }
};

createBoard();
.tile {
  display: inline-block;
  height: 25vh;
  width: 30%;
  margin: 0 3px;
  border: 1px solid black;
}
<body>
  <div id="board"></div>
</body>

Что я думаю, что я должен делать (это не работает): https://jsfiddle.net/e4mstyy9/1/

// click-event
function changeColor(specificElement) {
  'use strict';
  specificElement.style.backgroundColor = 'yellow';
}

// create game
var gameContainer = document.getElementById('board');
var createBoard = function() {
  'use strict';
  var index, square;
  for (index = 0; index < 9; index += 1) {
    square = document.createElement('div');
    square.className = 'tile';

    // tile event
    square.addEventListener('click', changeColor(this));

    gameContainer.appendChild(square);
  }
};

createBoard();
.tile {
  display: inline-block;
  height: 25vh;
  width: 30%;
  margin: 0 3px;
  border: 1px solid black;
}
<body>
  <div id="board"></div>
</body>

1 ответ

Решение

Совет не создавать функции внутри цикла уместен только в том случае, если вы ссылаетесь на переменную цикла (или что-то, производное от этой переменной) внутри функции (см. Закрытие JavaScript внутри циклов - простой практический пример того, почему).

Но так как вы этого не делаете, ваш код в порядке, и вы можете продолжать его использовать.


Почему второй пример не работает?

Когда у вас есть такое выражение, как foo(bar()), bar будет вызван первым, и его возвращаемое значение будет передано foo,

В вашем коде у вас есть square.addEventListener('click', changeColor(this));, Это означает changeColor выполняется первым, и его возвращаемое значение передается addEventListener,

Тем не менее, двигатель даже не заходит так далеко, потому что выполнение changeColor(this) выдает ошибку

Uncaught TypeError: Невозможно прочитать свойство 'style' из undefined

Это потому, что ценность, которую вы передаете changeColor (this) не является элементом DOM. Поскольку вы используете строгий режим, значение this является undefinedтак что вы выполняете changeColor(undefined),

Одним из способов решения этой проблемы без создания функции внутри тела цикла было бы просто передать changeColor вместо того, чтобы называть это (что требует от нас использовать this снова):

// click-event
function changeColor() {
  this.style.backgroundColor = 'yellow';
}

// ...

square.addEventListener('click', changeColor);

На самом деле это хорошее изменение, поскольку функция создается только один раз и используется повторно, а не для создания нового обработчика событий для каждого элемента.

Другие вопросы по тегам