2017-10-31 19 views
0

나는 이벤트 리스너가 제거되지 않은 이유를 알지 못합니다. (정확하게 생각합니까?)removeEventListener(),하지만 리스너가 아직 있습니다.

배경 : 그것은는 자바 스크립트를 기반으로 https://github.com/webmarek/jsninja

가 : 주요 JS 파일의 대런 JONES

코드에 의해 NINJA 초보자 (조금 아래로 스크롤하고 TLDR 참조) 여기에 전체 프로젝트에 대한 링크는 다음과 같습니다

(function() { 
    "use strict" 
//// dom references //// 

    var $question = document.getElementById("question"); 
    var $score = document.getElementById("score"); 
    var $feedback = document.getElementById("feedback"); 
    var $start = document.getElementById("start"); 
    var $form = document.getElementById("answer"); 
    var $timer = document.getElementById("timer"); 


    var quiz = { 
     "name": "Super Hero Name Quiz", 
     "description": "How many super heroes can you name?", 
     "question": "What is the real name of ", 
     "questions": [ 
      {"question": "Superman", "answer": "Clarke Kent", "asked": false}, 
      {"question": "Batman", "answer": "Bruce Wayne", "asked": false}, 
      {"question": "Wonder Woman", "answer": "Dianna Prince", "asked": false}, 
      {"question": "Spider Man", "answer": "Peter Parker", "asked": false}, 
      {"question": "Iron Man", "answer": "Tony Stark", "asked": false}, 
     ] 
    }; 

    var question; // current question 
    var initialScore = 0; // initialize score 

    var i = 0; //initialize counter of questions... maybe we can make it so it isn't global variable 
/// view functions /// 
    function update(element, content, klass) { 
     console.trace(); 
     var p = element.firstChild || document.createElement("p"); //firstChild works, because every element in HTM file has been created without any whitespaces inside 
     p.textContent = content; 
     element.appendChild(p); 
     if (klass) { 
      p.className = klass; 
     } 
    } 

//helper functions 
    function hide(element) { 
     element.style.display = "none"; 
    } 

    function show(element) { 
     element.style.display = "block"; 
    } 


// hide the form at the start of the game 
    hide($form); 

//hide the timer 
    hide($timer); 


//random function 

    function random(a, b, callback) { 
     if (b === undefined) { 
      // if only one argument is supplied, assume the lower limit is 1 
      b = a, a = 1; 
     } 
     var result = Math.floor((b - a + 1) * Math.random()) + a; 
     if (typeof callback === "function") { 
      result = callback(result); 
     } 
     return result; 
    } 

//play function 
    function Game(quiz) { 
     //first lets set some properties 
     this.questions = quiz.questions; 
     this.phrase = quiz.question; 
     this.score = 0;//initialize score 
     update($score, this.score); //and make it visible 

     // initialize timer and set up an interval that counts down 
     this.time = 20; 
     update($timer, this.time); 
     this.interval = window.setInterval(this.countDown.bind(this), 1000); 

     // hide button, and show form and feedback and timer, besides, feedback needs to be cleared. 
     hide($start); 
     show($form); 
     show($timer); 
     $feedback.innerHTML = ""; 
     show($feedback); 


     // add event listener to form for when it's submitted 

     $form.addEventListener('click', this.onClickFireCheck.bind(this), false); 

     this.chooseQuestion(); 
    } 

    //here we fumble in the Game.prototype 
    Game.prototype.chooseQuestion = function() { 
     console.log("chooseQuestion() invoked"); 
     var questions = this.questions.filter(function (question) { 
      return question.asked === false; 
     }); 

     // set the current question 
     this.question = questions[random(questions.length) - 1]; 
     this.ask(this.question); 
    } 

    Game.prototype.ask = function (question) { 
     console.log("ask() invoked"); 

     var quiz = this; 

     // set the question.asked property to true so it's not asked again 
     question.asked = true; 
     update($question, this.phrase + question.question + '?'); 

     //NOW CLEAR THE FUCKING FORM, YO... 
     $form.innerHTML = ""; 

     // create an array to put the different options in and a button variable 
     var options = [], button; 
     var option1 = chooseOption(); 
     options.push(option1.answer); 
     var option2 = chooseOption(); 
     options.push(option2.answer); 
     // add the actual answer at a random place in the options array 
     options.splice(random(0, 2), 0, question.answer); 

     // loop through each option and display it as a button 
     options.forEach(function (name) { 
      button = document.createElement("button"); 
      button.value = name; 
      button.textContent = name; 
      $form.appendChild(button); 
     }); 

     // choose an option from all the possible answers but without choosing the same option twice. We have to choose one of the objects randomly, to find proposition for answer that lays within. 
     function chooseOption() { 
      var option = quiz.questions[random(quiz.questions.length) - 1]; 
      // check to see if the option chosen is the current question or already one of the options, if it is then recursively call this function until it isn't 
      if (option === question || options.indexOf(option.answer) !== -1) { 
       return chooseOption(); 
      } 
      return option; 
     } 
    } 

    Game.prototype.check = function (answer) { 
     console.log("check() invoked"); 
     //ternaries 
     answer === this.question.answer ? (
       update($feedback, "Correct!", "right"), 
        // increase score by 1 
        this.score++, 
        update($score, this.score)) 
      : (
       update($feedback, "Wrong!", "wrong") 
      ) 
     i++; 
     //now how the hell do I check if thats last answer? 
     (i === quiz.questions.length) ? (
      this.gameOver() 
     ) : (
      this.chooseQuestion() 
     ) 
    } 

    Game.prototype.countDown = function() { 
     // decrease time by 1 
     this.time--; 
     // update the time displayed 
     update($timer, this.time); 
     // the game is over if the timer has reached 0 
     if (this.time <= 0) { 
      this.gameOver(); 
     } 
    } 

    Game.prototype.onClickFireCheck = function (e) { 
     this.check(e.target.value); 
    } 

    Game.prototype.gameOver = function(){ 
     console.log("gameOver() invoked"); 
     // inform the player that the game has finished and tell them how many points they have scored 
     update($question, "Game Over, you scored " + this.score + " points"); 

     hide($form); 
     hide($timer); 
     show($start); 

     // stop the countdown interval 
     window.clearInterval(this.interval); 

     //reset questions counter 
     i = 0; 

     this.questions.forEach(function (question) { 
      question.asked = false; 
     }); 

     //remove event listener from $form 
     $form.removeEventListener("click", this.onClickFireCheck.bind(this), false); 
    } 


// Event listeners 
    $start.addEventListener('click', function() { 
     new Game(quiz); 
    }, false); 

    update($score, initialScore); 

    //stop the automatic refresh of page when the form is submitted. 
    $form.addEventListener("submit", function (e) { 
     e.preventDefault(); 
    }, false); 

}()); 

이제 TL; DR :이 게임을 처음 플레이 할 때 , 그 괜찮 실행. 5 가지 질문이 있습니다. 내가 다시 게임을 할 때, 그것은 모든 정당한 질문 (5 대신에 3을 좋아한다)을 요구하지 않으며 게임이 끝난다.

한 번 더 재생하고 1 ~ 2 개의 질문을 제기합니다.

정보 : 콘솔에서 확인한 결과 게임을 할 때마다처럼 보이지만 ('클릭'수신 대기하는) 이벤트 수신기는 $form에 추가됩니다. 코드의 바닥에

print console

, gameOver 방법에 나는 그것을 제거하고 있습니다. 그러나 3 번 연주 한 후 그 중 3 명이 이벤트 리스너입니다.

removeEventListener에 전달 된 두 번째 인수에서 .bind(this)을 제거했는데 도움이되지 않았습니다.

답변

0

.bind()addEventListener에 전달하는 함수가 removeEventListener으로 전달하는 것과 다른 ID를 가지므로 새 고유 함수 객체를 만듭니다.

핸들러를 바인딩 해제하려면 과 동일한 함수 객체를 전달해야합니다.

귀하의 목적은 Game 인스턴스에 this을 설정하는 것이므로 여기에서 다른 방법을 사용할 수 있습니다. 대신 handleEvent 메서드를 Game.prototype에 추가합니다.이 메서드를 클릭하면 원하는 메서드가 호출됩니다.

Game.prototype.handleEvent = function(event) { 
    if (event.type === "click") { 
    this.onClickFireCheck(event); 
    } 
}; 

그런 다음 add/remove 메서드 대신 인스턴스 자체.

$form.addEventListener('click', this, false); 
// ... 
$form.removeEventListener('click', this, false); 

이제 이벤트가 발생하면, 그것은 this 값을 설정 Game 인스턴스를해야합니다 새로운 handleEvent 메소드를 호출 할 수 있습니다. 이를 통해 바인딩 한 인스턴스와 직접 상호 작용할 수 있으며 리스너를 제거 할 때 동일한 객체를 전달할 수 있습니다.

+0

신속하고 정확하게. 그리고 일하고있어! –

+0

도움이 되니 기쁩니다. – llama