JavaScript Class 属性 和方法具有相同的名称

JavaScript Class with same name for property and method

在研究问题时,我 运行 试图删除使用 bind() 的事件侦听器,类似于下面 class 构造函数使用的语法(我不是在尝试删除这个,但如果我尝试它不会成功),我发现两个来源显示了一个类似于下面的 onDown 方法使用的解决方案(我确实希望一旦不再需要就删除这个)创建执行绑定的单独函数,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.

的条目

如果我构建的另一个测试对象的输出预计会失败,这是另一张图片。在这里你可以看到它是用相同的设计建造的;它有一个名为 sameName 的 属性 (可以引用)并且它在 Prototype 下有一个方法也名为 sameName (调用时失败)。

这次失败符合预期。但是同样,在我的第一个示例中,有一个 属性 和一个方法,它们都具有相同的名称 onUp,并且该方法确实起作用。

方法只是一个 属性 及其值的函数。

属性 是附加到对象的命名“事物”。

当您在 JavaScript 中创建 class 的实例时(即使用 new 关键字调用函数),它会创建一个具有 原型的对象 这是对 class.

的引用

当您尝试访问对象上的 属性 时,它首先会检查对象本身是否有这样的 属性。如果找不到它,它会查看原型并检查该对象是否有具有该名称的 属性。然后它检查该对象的原型等等,直到用完原型链上的对象。

这就是继承在 JavaScript 中的工作方式。

————

因此,当您调用 new TestClass 时,您创建了一个对象,该对象的原型具有 onUp 方法。

当 mousedown 事件触发时,您说:

this.onUp = this.onUp.bind(this, id);

其中:

  1. 在对象上寻找 onUp 但未找到
  2. 查找原型链
  3. 在通话中找到它
  4. 对其调用 bind 以创建新函数
  5. 将该函数复制到对象本身的 onUp 属性(创建它)

现在你在对象本身和原型链上的对象上有了一个 onUp 属性。

这通常不是问题,但在您的特定情况下,它会导致效率低下。

第二次触发 mousedown 事件时,它会在对象本身上找到 onUp,但仍会对其调用 bind 以创建一个新函数(调用前一个函数调用前一个函数功能)。

每次发生另一个 mousedown 事件时,您都会获得额外的绑定层。

您可以通过使用 hasOwnProperty 方法进行测试来避免这种情况(它会告诉您该值是否存在于对象本身而不是原型链上)。