Переменная Javascript не определена - PullRequest
0 голосов
/ 15 сентября 2018

почему всегда говорят "1001 *, когда я двигаю мышь?Это должно вернуть истину, верно?Я надеюсь, что кто-нибудь может мне помочь :) Прежде чем вы спросите, я позвонил классу в другой файл JavaScript!

class Block {

 constructor() {

    this.movable = true;
    this.move = false;

    this.div = document.createElement("div");
    this.div.classList.add("block");

    this.div.addEventListener("mousemove", function() {

        console.log(this.movable); 

    });
    this.div.addEventListener("mousedown", function() {

        this.move = true;
        console.log("test");

    });
    this.div.addEventListener("mouseup", function() {

        this.move = false;
        console.log("test1");

    });

 }
 add() {

     document.body.appendChild(this.div);

 }
 remove() {

     document.body.removeChild(this.div);

 }

}

Ответы [ 4 ]

0 голосов
/ 15 сентября 2018

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

У вас есть три способа исправить это , два из которых основаны на ES5, один из них основан на ES6 (что не должно быть проблемой - вы уже используете ES6 в своем коде).

1 Явно привяжите внешний this к функциям вашего обработчика, используя Function.prototype.bind().

bind(), который сообщает функциям, что использовать в качестве this внутри тела функции.

class Test {
  constructor() {
    this.movable = true;
    this.move = false;
    this.div = document.createElement("div");
    this.div.classList.add("block");
    this.div.addEventListener("mousemove", function() {
      console.log(this.movable);
    }.bind(this)); // .bind(this)
    this.div.addEventListener("mousedown", function() {
      this.move = true;
      console.log("test");
    }.bind(this)); // .bind(this)
    this.div.addEventListener("mouseup", function() {
      this.move = false;
      console.log("test1");
    }.bind(this)); // .bind(this)
  }
  add() {
    this.div.textContent = "Test";
    document.body.appendChild(this.div);
  }
  remove() {
    document.body.removeChild(this.div);
  }
}
var test = new Test();
test.add();
<body>
</body>

2 Сохраните ссылку на экземпляр класса в переменной (здесь: self) и используйте ее внутри функции-обработчика.

Раньше это был очень распространенный шаблон для решения проблемы, с которой вы столкнулись.Сейчас, когда все прыгают на поезд ES6, он все меньше и меньше используется.Мне нравится это также для улучшения читаемости.

class Test {
  constructor() {
    const self = this; // reference to this stored in self
    this.movable = true;
    this.move = false;
    this.div = document.createElement("div");
    this.div.classList.add("block");
    this.div.addEventListener("mousemove", function() {
      console.log(self.movable); // self instead of this used
    });
    this.div.addEventListener("mousedown", function() {
      self.move = true; // self instead of this used
      console.log("test");
    });
    this.div.addEventListener("mouseup", fucntion() {
      self.move = false; // self instead of this used
      console.log("test1");
    });
  }
  add() {
    this.div.textContent = "Test";
    document.body.appendChild(this.div);
  }
  remove() {
    document.body.removeChild(this.div);
  }
}
var test = new Test();
test.add();
<body>
</body>

3 Использовать синтаксис функции стрелки ES6.

Функции стрелок не имеют своих собственных this (что может быть недостатком в некоторыхслучаи!), что делает "внешний" this доступным для них.

class Test {
  constructor() {
    this.movable = true;
    this.move = false;
    this.div = document.createElement("div");
    this.div.classList.add("block");
    this.div.addEventListener("mousemove", () => {
      console.log(this.movable);
    });
    this.div.addEventListener("mousedown", () => {
      this.move = true;
      console.log("test");
    });
    this.div.addEventListener("mouseup", () => {
      this.move = false;
      console.log("test1");
    });
  }
  add() {
    this.div.textContent = "Test";
    document.body.appendChild(this.div);
  }
  remove() {
    document.body.removeChild(this.div);
  }
}
var test = new Test();
test.add();
<body>
</body>

Как уже упоминалось, если не использовать функции стрелок для определения обработчиков событий, this внутри обработчика будет обычно содержать ссылку на элемент, вызвавший событиена (что часто очень полезно).Чтобы получить к ней доступ, несмотря на использование функций стрелок, вы можете использовать свойство event.target:

// notice I name a parameter e here
// which will hold the event object
// that is always passed to the event
// handler automatically - it just needs 
// a name to make it accessible inside
(e) => { console.log(e.target); }
0 голосов
/ 15 сентября 2018

Это из-за this определения объема.

Оказывается, this из вашего конструктора не совпадает с тем из вашего обратного вызова:

class Block {
    constructor() {
        // here this is your instance of your class block
        this.movable = true;


        this.div.addEventListener("mousemove", function() {
            // here it's not since each function get's it's own from how it's called
            // since it is called by `div.addEventListener` and not you directly
            // JS had no way to get the root this
            console.log(this.movable); 

        });
    }
}

Самое простое решение - использовать ES6 функции стрелок.

class Block {
    constructor() {
        // here this is your instance of your class block
        this.movable = true;


        this.div.addEventListener("mousemove", () => {
            // this is bound to your instance of class block in this scope too !
            console.log(this.movable); 
        });
    }
}

Обратите внимание на () => { вместо function () {!

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

0 голосов
/ 15 сентября 2018

Вы можете использовать функцию стрелки ES6 ()=>{} для решения вашей проблемы.Функция стрелки использует this текущего контекста выполнения.В данном случае это экземпляр class с инициализированным свойством movable.

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

class Test{

 constructor() {
      this.movable = true;
      this.move = false;

      this.div = document.createElement("div");
    
      this.div.classList.add("block");

      this.div.addEventListener("mousemove", ()=> {
          console.log(this.movable); 
      });
      this.div.addEventListener("mousedown", ()=> {
          this.move = true;
          console.log("test");
      });
      this.div.addEventListener("mouseup", ()=> {
          this.move = false;
          console.log("test1");
      });
    }

 add(){
     this.div.textContent ="Hover over me.";
     document.body.appendChild(this.div);
 }

 remove(){
     document.body.removeChild(this.div);
 }

}
var test = new Test();
test.add();
<body>
</body>

Цитирование из MDN:

Выражение функции со стрелкой имеет более короткий синтаксис, чем выражение функции, и не имеет своего собственного this, аргументы, супер или new.target.Эти функциональные выражения лучше всего подходят для функций, не относящихся к методам, и их нельзя использовать в качестве конструкторов.

0 голосов
/ 15 сентября 2018

Вы должны изучить контекст javascript.

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

ссылка: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this#bind_method

class Block {
    constructor() {
        this.movable = true;
        this.move = false;

        this.div = document.createElement("div");
        this.div.classList.add("block");

        this.div.addEventListener("mousemove", function() {
            console.log(this.movable); 
        }.bind(this)); // bind this!!
        this.div.addEventListener("mousedown", function() {
            this.move = true;
            console.log("test");
        }.bind(this)); // bind this!!
        this.div.addEventListener("mouseup", function() {
            this.move = false;
            console.log("test1");
        }.bind(this)); // bind this!!

    }
    add() {
        document.body.appendChild(this.div);
    }
    remove() {
        document.body.removeChild(this.div);
    }
}
...