自定义元素原型中的重写函数会更改 this 对象

Overriding function in prototype of custom element changes the this object

我制作了一个自定义元素 class,然后尝试在原型级别包装其中一个函数,以便每个实例都使用包装器。但是,当我这样做时, this 的值在函数内部发生了变化。如何更改原型函数并访问新函数内部的实例 this

在此示例中,每次我在 MyClass2 中记录 this 时,我希望它打印 <my-class-2></my-class-2>,就像我在 [=19= 中记录 this 时一样] 它打印 <my-class></my-class>.

Here's a fiddle as well.

class MyClass extends HTMLElement {
    connectedCallback() {
        console.log('Inside MyClass:')
        console.log(this)
    }
}

customElements.define('my-class', MyClass)


class MyClass2 extends HTMLElement {
    connectedCallback() {
        console.log('Inside MyClass2:')
        console.log(this)
    }
}

let connectedCallback = MyClass.prototype.connectedCallback
MyClass2.prototype.connectedCallback = () => {
    console.log('Outside MyClass2')
    console.log(this)
    connectedCallback()
}

customElements.define('my-class-2', MyClass2)
<my-class></my-class>
<my-class-2></my-class-2>

控制台输出:

Inside MyClass:
<my-class>​</my-class>​
Outside MyClass2
Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: global, …}
Inside MyClass:
undefined

首先,当你重新定义connectedCallback()方法时,你不能使用箭头函数,因为箭头函数调用不会设置[=16的值=] 到对象的引用。

这通常是一个优势,但在这里不是。而是使用经典的 function () 表示法:

 MyClass2.prototype.connectedCallback = function() {
     console.log(this)
 }

其次,当您编写 let connectedCallback = MyClass.prototype.connectedCallback 时,实际上您断开了引用函数与对象的连接。

因此,this 不会从调用它的地方引用对象,而是引用当前上下文 window

相反,您可以使用 bind() 在调用方法之前使用对象的值设置 this

 MyClass2.prototype.connectedCallback = function() {
     connectedCallback.bind(this)()
 }    

或者,您可以将函数定义为当前对象的方法。

 MyClass2.prototype.connectedCallback_old = MyClass.prototype.connectedCallback
 MyClass2.prototype.connectedCallback = function() {
     this.connectedCallback_old()
 }    

class MyClass extends HTMLElement {
    connectedCallback() {
        console.log('Inside MyClass:')
        console.log(this)
    }
}

customElements.define('my-class', MyClass)


class MyClass2 extends HTMLElement {
    connectedCallback() {
        console.log('Inside MyClass2:')
        console.log(this)
    }
}

let connectedCallback = MyClass.prototype.connectedCallback
MyClass2.prototype.connectedCallback = function () {
    console.log('Outside MyClass2')
    console.log(this)
    connectedCallback.bind(this)()
}

customElements.define('my-class-2', MyClass2)
<my-class></my-class>
<my-class-2></my-class-2>