在研究一个问题时,我在尝试删除使用 bind()
的事件监听器时遇到了一个问题,该事件监听器类似于下面类构造函数所使用的语法(我不是要删除这个,但如果我尝试了它不会成功),我发现两个来源显示了一个类似于下面的 onDown 方法使用的解决方案(我确实希望在不再需要时删除这个)创建一个单独的函数绑定(bind)和 addEventListener
通过名称附加函数:
class TestClass {
constructor(el) {
el.addEventListener('mousedown', function () { this.onDown(el.id) }.bind(this));
}
onDown(id) {
// Here a property named onUp is created:
this.onUp = this.onUp.bind(this, id);
document.addEventListener('mouseup', this.onUp);
}
// Here a method named onUp is defined in the class:
onUp(id) {
document.removeEventListener('mouseup', this.onUp);
console.log("Mouse down on " + id + " and then mouse up.");
}
}
const d1 = new TestClass(document.getElementById("div1"));
const d2 = new TestClass(document.getElementById("div2"));
<div id="div1">Div 1: Click me and let go!</div>
<div id="div2">Div 2: Click me and let go!</div>
这段代码有效并达到了我想要的结果,但我观察到这会在创建的对象中创建一个同名的属性和方法,名为 onUp
。这也可以通过查看创建的对象的属性来验证(见下图)。这是不可能的,正如在此处调用使用与属性相同名称的方法时收到的错误所确认的那样:
class Test {
sameName = "property";
sameName() { return "method"; }
}
const testObject = new Test();
console.log(testObject.sameName); // Here Console outputs the value of the sameName property
console.log(testObject.sameName()); // This fails calling the sameName() method
谁能帮我解释一下在第一个例子中这是如何工作的,其中一个对象具有同名的属性和方法?这是个问题吗?
请注意,我也有其他方法可以做到这一点。否则我可以简单地给其中之一起一个不同的名字:
onDown(el) {
this._onUp = this.onUp.bind(this, el);
document.addEventListener('mouseup', this._onUp);
}
onUp(el) {
document.removeEventListener('mouseup', this._onUp);
console.log("Mouse down on " + el.id + " and then mouse up.");
}
或者,{ once: true }
选项适用于该示例,但不适用于我正在编写的使用不同事件的实际代码(这只是一个简化的示例):
onDown(el) {
document.addEventListener('mouseup', function () { this.onUp(el) }.bind(this), { once: true });
}
onUp(el) {
console.log("Mouse down on " + el.id + " and then mouse up.");
}
添加一张图像,显示其中一个 TestClass 对象的输出属性。它首先列出属性值。由于我的示例只有 1 个属性,因此我添加了另一个(名为 anotherProperty
)来显示属性集合,以进行控制。在 Prototype 下,它列出了对象中的所有方法。这两个部分都有一个名为 onUp
的条目。
如果我构建的其他测试对象的输出预计会失败,这是另一张图片。在这里你可以看到它是用相同的设计 build 的;它有一个名为 sameName
的属性(可以引用)并且它在 Prototype 下有一个方法也命名为 sameName
(调用时失败)。
此故障符合预期。但是同样,在我的第一个示例中,有一个属性和一个方法,它们的名称相同,onUp
,并且该方法确实起作用。
最佳答案
方法只是一个属性及其值的函数。
属性是附加到对象的命名“事物”。
当您在 JavaScript 中创建一个类的实例时(即使用 new
关键字调用一个函数),它会创建一个具有原型(prototype) 的对象,它是对类。
当您尝试访问对象的属性时,它首先会检查对象本身,看它是否具有这样的属性。如果找不到,它会查看原型(prototype)并检查该对象是否具有该名称的属性。然后它会检查该对象的原型(prototype)等等,直到用完原型(prototype)链上的所有对象。
这就是继承在 JavaScript 中的工作方式。
————
因此,当您调用 new TestClass
时,您会创建一个对象,该对象的原型(prototype)具有 onUp
方法。
当 mousedown 事件触发时,您说:
this.onUp = this.onUp.bind(this, id);
哪个:
- 在对象上寻找
onUp
但没有找到 - 查找原型(prototype)链
- 在通话中找到它
- 调用
bind
来创建一个新函数 - 将该函数复制到对象本身的
onUp
属性(创建它)
现在对象本身和原型(prototype)链上的对象都有一个 onUp
属性。
这通常不是问题,但在您的特定情况下,它会导致效率低下。
第二次触发 mousedown 事件时,它会在对象本身上找到 onUp
,但仍会对其调用 bind
以创建一个新函数(调用前一个函数调用前一个函数)。
每次发生另一个 mousedown 事件时,您都会获得一个额外的绑定(bind)层。
您可以通过使用 hasOwnProperty
方法进行测试来避免这种情况(它将告诉您该值是否存在于对象本身而不是原型(prototype)链上)。
关于属性和方法具有相同名称的 JavaScript 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71025869/