В JavaScript методе класса, Невозможно использовать 'this' внутри addEventListener (), даже используя функции стрелок. как решить эту проблему - PullRequest
0 голосов
/ 30 апреля 2020

Я написал класс для игры Ti c Ta c Toe. код работает нормально, но мне пришлось использовать имя объекта внутри определения класса для вызова некоторых методов вместо ключевого слова this. проблема возникает, когда метод передается как обратный вызов для addEventListener (). Я попытался решить ее, определив методы с помощью функций стрелок. Но JS показывает ошибку «не удается прочитать свойство неопределенного». Как бы я преодолел эту ситуацию?

здесь - реализация класса. вы можете видеть, что я использовал game.turnClick вместо this.turnClick

    class TicTacToe{
    constructor(aiPlayer,humanPlayer){

        this.aiPlayer=aiPlayer;
        this.humanPlayer=humanPlayer;
        this.winCombos=[
            [0,1,2],
            [3,4,5],
            [6,7,8],
            [0,3,6],
            [1,4,7],
            [2,5,8],
            [0,4,8],
            [2,4,6]
        ];
        this.originalBoard=Array.from(Array(9).keys());
        this.gameWon=null;
        this.cells=document.querySelectorAll('.cell');


    }
    startGame(){
        //const cells=document.querySelectorAll('.cell');
        this.cells.forEach(function(cell){
            cell.innerHTML="";
            cell.addEventListener('click',game.turnClick);
        })
    }
    turnClick(e){
        game.turn(e.target.id,game.humanPlayer);
        if(!game.isTie()&&!game.gameWon){
            window.setTimeout(function(){
                game.turn(game.bestSquare(),game.aiPlayer);
                game.isTie();
            },1500);

        }
    }
    turn(squareId,player){
        this.originalBoard[squareId]=player;
        const square=document.getElementById(squareId);
        square.innerHTML=player;
        document.querySelector('#click').play();
        square.removeEventListener('click',game.turnClick);
        this.gameWon=this.checkWin(this.originalBoard,player);
        if(this.gameWon){
            this.gameOver();
        }



    }
    checkWin(board,player){
        let playedSquares=[];
        board.forEach(function(el,i){
            if(el===player){
                playedSquares.push(i);
            }
        })
        console.log(playedSquares);
        for(let [index,win] of this.winCombos.entries()){
            if(win.every((el)=>{return playedSquares.includes(el)})){
            return {index,player};
            break;
            }
        }
        return null;
    }
    gameOver(){
        for(let index of this.winCombos[this.gameWon.index] ){
            const square=document.getElementById(index);
            square.style.backgroundColor= this.gameWon.player===this.humanPlayer?"blue":"red";
        }
        //const cells=document.querySelectorAll('button.cell');
        this.cells.forEach(function(cell){
            cell.removeEventListener('click',game.turnClick);
        });
        this.declareWin(this.gameWon.player===this.humanPlayer?'You Won !!! Hurray...':'You loose,AI beat you...');
    }
    emptySquares(){
        return this.originalBoard.filter((el)=>typeof el==='number');
    }
    bestSquare(){
        //return this.emptySquares()[0];
        return this.minimax(this.originalBoard, this.aiPlayer).index;
    }
    isTie(){
        if(this.emptySquares().length===0&& !this.gameWon){
            this.cells.forEach(function(cell){
                cell.style.backgroundColor='green';
                cell.removeEventListener('click',game.turnClick);
            });
            this.declareWin(' You managed tie the game. congrats !!!');
            return true;
        }
        else{
            return false;
        }
    }
    declareWin(msg){
        if(msg.includes('won')||msg.includes('tie')){
            document.querySelector('#winOrTie').play();
        }
        else{
            document.querySelector('#lost').play();
        }
        document.querySelector('.endgame .message').innerText=msg;
        document.querySelector('.endgame').classList.add('show');
    }
    minimax(newBoard,player){
        let availSpots = this.emptySquares();

        if (this.checkWin(newBoard, this.humanPlayer)) {
            return {score: -10};
        } else if (this.checkWin(newBoard, this.aiPlayer)) {
            return {score: 10};
        } else if (availSpots.length === 0) {
            return {score: 0};
        }
        let moves = [];
        for (let i = 0; i < availSpots.length; i++) {
            let move = {};
            move.index = newBoard[availSpots[i]];
            newBoard[availSpots[i]] = player;

            if (player === this.aiPlayer) {
                let result = this.minimax(newBoard, this.humanPlayer);
                move.score = result.score;
            } else {
                let result = this.minimax(newBoard, this.aiPlayer);
                move.score = result.score;
            }

            newBoard[availSpots[i]] = move.index;

            moves.push(move);
        }

        let bestMove;
        if(player === this.aiPlayer) {
            let bestScore = -10000;
            for(let i = 0; i < moves.length; i++) {
                if (moves[i].score > bestScore) {
                    bestScore = moves[i].score;
                    bestMove = i;
                }
            }
        } else {
            let bestScore = 10000;
            for(let i = 0; i < moves.length; i++) {
                if (moves[i].score < bestScore) {
                    bestScore = moves[i].score;
                    bestMove = i;
                }
            }
        }

        return moves[bestMove];

    }
}

здесь находится репозиторий gitHub, содержащий полный код https://github.com/harikrishnan-a-k/Tic_Tac_Toe

1 Ответ

1 голос
/ 30 апреля 2020
cell.addEventListener('click',game.turnClick.bind(game));

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

...