I have the following code, where I would like to replace all main references in animate to this references, to avoid using a global variable inside the Main class:
class Main {
constructor(idDiv) {
this.div = document.getElementById(idDiv);
this.sceneManager = new SceneManager(this.div);
}
animate() {
console.log('Main::animate::this', this);
console.log('Main::animate::main', main);
requestAnimationFrame(main.animate);
main.sceneManager.animate();
}
execute() {
new ManageEvents(this.div, this.sceneManager);
const atla = new Atla();
const repository = new Repository();
const loadData = new LoadData(atla, repository);
loadData.load(this.sceneManager);
console.log('Main::execute::this', this);
console.log('Main::execute::main', main);
this.animate(main.sceneManager);
}
}
const main = new Main('original');
main.execute();
Currently the previous code creates an animation loop which uses THREEjs animate to render a scene.
In addition, currently the logs are:
In execute:
Main::execute::this Main {div: div#original.column, sceneManager: SceneManager}div: div#original.columnsceneManager: SceneManager {div: div#original.column, camera: PerspectiveCamera, scene: Scene, controls: T…E.TrackballControls, renderer: WebGLRenderer}__proto__: Object
Main::execute::main Main {div: div#original.column, sceneManager: SceneManager}
In animate, first call:
Main::animate::this Main {div: div#original.column, sceneManager: SceneManager}
Main.js:16 Main::animate::main Main {div: div#original.column, sceneManager: SceneManager}
In animate, others calls:
Main::animate::this null
Main.js:16 Main::animate::main Main {div: div#original.column, sceneManager: SceneManager}
So as we see in the first call both this and main are the same, in both execute and animate functions. Then in the others calls, the this in animate is null and the main stills being the instance of the Main class. I assumme it is because of the line:
requestAnimationFrame(main.animate);
Where we are losing the this.
In addittion, to replace the main references I tried:
class Main {
constructor(idDiv) {
this.div = document.getElementById(idDiv);
this.sceneManager = new SceneManager(this.div);
}
animate(main) {
console.log('Main::animate::this', this);
console.log('Main::animate::main', main);
requestAnimationFrame(main.animate);
main.sceneManager.animate();
}
execute() {
new ManageEvents(this.div, this.sceneManager);
const atla = new Atla();
const repository = new Repository();
const loadData = new LoadData(atla, repository);
loadData.load(this.sceneManager);
console.log('Main::execute::this', this);
console.log('Main::execute::main', main);
this.animate(this);
}
}
const main = new Main('original');
main.execute();
To change the parameter being passed in to animate to reference the this, the current Main instance.
Its results are the following:
First call:
Main::execute::this Main {div: div#original.column, sceneManager: SceneManager}
Main.js:34 Main::execute::main Main {div: div#original.column, sceneManager: SceneManager}
Main.js:15 Main::animate::this Main {div: div#original.column, sceneManager: SceneManager}
Main.js:16 Main::animate::main Main {div: div#original.column, sceneManager: SceneManager}
Second call:
Main::animate::this null
Main.js:16 Main::animate::main 697.568
Main.js:17 Uncaught TypeError: Failed to execute 'requestAnimationFrame' on 'Window': The callback provided as parameter 1 is not a function.
at animate (Main.js:17)
I understood that is is because of in the line:
requestAnimationFrame(main.animate);
We are not passing in our main again so I did:
...
requestAnimationFrame(main.animate(main));
...
However it generates an infinite loop where we cannot see the scene anymore. Also logs are:
Main::execute::this Main {div: div#original.column, sceneManager: SceneManager}
Main.js:34 Main::execute::main Main {div: div#original.column, sceneManager: SceneManager}
Main.js:15 Main::animate::this Main {div: div#original.column, sceneManager: SceneManager}
Main.js:16 Main::animate::main Main {div: div#original.column, sceneManager: SceneManager}
Main.js:15 Main::animate::this Main {div: div#original.column, sceneManager: SceneManager}
Main.js:16 Main::animate::main Main {div: div#original.column, sceneManager: SceneManager}
Main.js:15 Main::animate::this Main {div: div#original.column, sceneManager: SceneManager}
Main.js:16 Main::animate::main Main {div: div#original.column, sceneManager: SceneManager}
Main.js:15 Main::animate::this Main {div: div#original.column, sceneManager: SceneManager}
Main.js:16 Main::animate::main Main {div: div#original.column, sceneManager: SceneManager}
I have also read:
ES6 Class: access to 'this' with 'addEventListener' applied on method
How to call .render and .animate functions inside object class?
How to create closure (protect globals) in an animation loop?
What am I doing wrong?
Could you help me please?