Just getting started with ES6 classes. As far as I understood it, this was supposed to behave predictably inside a class and always point to the object. However, that doesn't seem to be the case:
class BodyPixController {
#target; //Declare a private property
constructor(target){
this.#target = target; // Set the property
console.log(this); // logs: BodyPixController {#target: 'photo'}
addEventListener('load', this.init); // Calls the method
}
init() {
console.log(this); // logs: Window {window: Window, self: Window, document: document, name: '', location: Location,…}
const img = document.getElementById(this.#target); // Throws error: Cannot read private member #target from an object whose class did not declare it
console.log(img);
async function loadAndPredict() {
const net = await bodyPix.load( /** optional arguments, see below **/ );
const segmentation = await net.segmentPerson(img);
console.log(segmentation);
}
loadAndPredict();
}
}
In the code above, this only points to the instantiated object inside the constructor. As soon as the init() method is called, this points to Window. Why? And how do I access private properties from inside methods?
CodePudding user response:
this
inside event listeners refer to the object that the listener is attached to in case of the load
event the Window
.
Either pass event listener as arrow function as they have no scope or bind this to your function in constructor like:
constructor() {
// bind this inside init to current object
this.init = this.init.bind(this);
addEventListener('load', this.init);
}
CodePudding user response:
"as far as I understood it", it's all in the docs.
Classes arent special, just syntactic sugar, so when you pass that function to the event listener, it wont be calling "yourObj.func()", just "func()" (for simplicity), it has no reference to your object.
You're thinking of ES6 functions, which are special. Change init() {
to init = () => {
and it'll behave how you want; this
will always refer to your instantiated class object (not even .apply()
can override).
CodePudding user response:
Perhaps you can work with this. I created a class and added an event handler; then created an instance of the class and triggered one of the events.
So here we have an event target e.target
and this
as things to work with.
class BodyPixController {
constructor(target) {
this.target = target;
console.log(this);
this.target.addEventListener('load', this);
}
boundLoad = () => this.loadEvent()
boundInit = this.init.bind(this)
init(e) {
console.log(e);
const img = document.getElementById(e.target);
console.log(img);
async function loadAndPredict() {
const net = await bodyPix.load( /** optional arguments, see below **/ );
const segmentation = await net.segmentPerson(img);
console.log(segmentation);
}
loadAndPredict();
}
loadEvent(e){
// Some action related to the event (e)
console.log(e.target);
console.log("loadEvent:",this);
console.log("What:",e.target.innerText);
}
handleEvent(e) {
switch (e.type) {
case "load":
this.loadEvent(e);
break;
case "init":
this.init(e);
break;
}
}
}
var target = document.querySelector(".fun-target");
var myInstance = new BodyPixController(target);
target.dispatchEvent(new CustomEvent('load'), {})
<div >howdy</div>