Javascript 变量未定义
Javascript Variable is not defined
为什么我移动鼠标总是提示undefined
?它应该 return 正确,对吧?我希望有人能帮助我 :)
在你问之前我在另一个 JavaScript 文件中调用了 class!
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);
}
}
你必须研究 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);
}
}
这是由于 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 () {
!
这是可行的,因为箭头函数没有它们自己的 this,而是保留它们可以访问它们创建位置的那个,非常方便。
你可以使用ES6箭头函数()=>{}
来解决你的问题。箭头函数使用当前执行上下文的 this
。在这种情况下,它是具有初始化 movable
属性.
的 class
的实例
普通匿名函数将使用侦听器附加到的对象的 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:
An arrow function expression has a shorter syntax than a function expression and does not have its own this, arguments, super, or new.target. These function expressions are best suited for non-method functions, and they cannot be used as constructors.
正如其他人提到的,你得到 undefined
的原因是 this
在你的事件处理函数中 而不是 class(如您所料)。
您有三种方法来解决这个问题,其中两种基于 ES5,一种基于 ES6(这应该不是问题 - 您正在使用 ES6已经在你的代码中了)。
1 使用 Function.prototype.bind()
.
将外部 this
显式绑定到您的处理程序函数
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 将对 class 实例的引用存储在变量中(此处: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); }
为什么我移动鼠标总是提示undefined
?它应该 return 正确,对吧?我希望有人能帮助我 :)
在你问之前我在另一个 JavaScript 文件中调用了 class!
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);
}
}
你必须研究 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);
}
}
这是由于 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 () {
!
这是可行的,因为箭头函数没有它们自己的 this,而是保留它们可以访问它们创建位置的那个,非常方便。
你可以使用ES6箭头函数()=>{}
来解决你的问题。箭头函数使用当前执行上下文的 this
。在这种情况下,它是具有初始化 movable
属性.
class
的实例
普通匿名函数将使用侦听器附加到的对象的 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:
An arrow function expression has a shorter syntax than a function expression and does not have its own this, arguments, super, or new.target. These function expressions are best suited for non-method functions, and they cannot be used as constructors.
正如其他人提到的,你得到 undefined
的原因是 this
在你的事件处理函数中 而不是 class(如您所料)。
您有三种方法来解决这个问题,其中两种基于 ES5,一种基于 ES6(这应该不是问题 - 您正在使用 ES6已经在你的代码中了)。
1 使用 Function.prototype.bind()
.
将外部 this
显式绑定到您的处理程序函数
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 将对 class 实例的引用存储在变量中(此处: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); }