I made a custom element class and then tried to wrap one of the functions at the prototype level so every instance would use the wrapper. However, when I do this, the value of this
changes inside the function. How can I change a prototype function and access the instance this
inside of the new function?
In this example, every time I log this
in MyClass2
I expect it to print <my-class-2></my-class-2>
, just like when I log this
in MyClass
it prints <my-class></my-class>
.
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>
Console output:
Inside MyClass:
<my-class></my-class>
Outside MyClass2
Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, parent: global, …}
Inside MyClass:
undefined
First, when you redefine the connectedCallback()
method, you must not use an arrow function, because arrow function calls won't set the value of this
to the reference of the object.
That's generally an advantage, but not here. Instead use the classic function ()
notation:
MyClass2.prototype.connectedCallback = function() {
console.log(this)
}
Second, when you write let connectedCallback = MyClass.prototype.connectedCallback
actually you disconnect the referenced function from the object.
As a consequence, this
won't reference the object from where it is call but the current context which is window
.
Instead, you can use bind()
to set this
with the value of the object, before calling the method:
MyClass2.prototype.connectedCallback = function() {
connectedCallback.bind(this)()
}
Alternately, you could define the function as a method of the current object.
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>