I is undefined in for loop that uses an eventListener with a function from a prototype

时间:2018-03-25 21:08:05

标签: javascript html

In my for loop I have an eventListener that is supposed to use the i that increases in the for loop, but the function in my eventListener, which is a prototype of the function in the for loop, is showing the i is undefined. I don't know how to fix this and would appreciate any help. Here is my code :

'use strict'

function game () {
  this.player = null;
  this.computer = null;
  this.playerMoves = [];
  this.computerMoves = [];
  this.squares = document.querySelectorAll('.play');
  this.winningCombos = [
[1, 2, 3],[4, 5, 6],[7, 8, 9],
[1, 4, 7],[2, 5, 8],[3, 6, 9],
[1, 5, 9],[3, 5, 7]
];

for(let i = 0; i < this.squares.length; i++){
  this.squares[i].addEventListener('click', this.playerMove());
 }
}

game.prototype.playerMove = function () {
        this.squares[i].textContent = this.player;
        //remove to prevent overwriting text content on computer move
        this.squares[i].classList.remove('play');
        this.computerMove();
}

const ticTacToe = new game();

1 个答案:

答案 0 :(得分:0)

You're immediately executing the function this.playerMove() which returns undefined.

this.squares[i].addEventListener('click', this.playerMove());
                                                         ^

Just pass the function as a handler. As you can see, this approach uses the function bind, this is to bind the current context this.

for(let i = 0; i < this.squares.length; i++){
  this.squares[i].addEventListener('click', this.playerMove);
}

Further, the variable i is out of scope within the function playerMove.

An alternative is passing the variable i as a parameter:

for(let i = 0; i < this.squares.length; i++){
  this.squares[i].addEventListener('click', (function() {
    this.playerMove(i);
  }).bind(this));
}

game.prototype.playerMove = function (i) {...}

Example to illustrate

function game() {
  this.player = 'Ele from SO';
  this.computer = null;
  this.playerMoves = [];
  this.computerMoves = [];
  this.squares = document.querySelectorAll('.play');
  this.winningCombos = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9],
    [1, 4, 7],
    [2, 5, 8],
    [3, 6, 9],
    [1, 5, 9],
    [3, 5, 7]
  ];

  for (let i = 0; i < this.squares.length; i++) {
    this.squares[i].addEventListener('click', (function() {
      this.playerMove(i);
    }).bind(this));
  }
}

game.prototype.playerMove = function(i) {
  console.log(i);
  this.squares[i].textContent = this.player;
  //remove to prevent overwriting text content on computer move
  this.squares[i].classList.remove('play');
  //this.computerMove(); // This is not function, it's an array instead.
}

const ticTacToe = new game();
<button class='play'>Click ME!</button>
<button class='play'>Click ME!</button>
<button class='play'>Click ME!</button>
<button class='play'>Click ME!</button>