After studying How do JavaScript closures work? and conducting experiments with variables in the Chrome console, I have come to the conclusion that "a closure is a stack frame which is allocated when a function starts its execution, and not freed after the function returns (as if a 'stack frame' were allocated on the heap rather than the stack!)" is a perfect way to explain this concept.
When I run 'app._scene.scene.children[0].rotateOnAxis' in the console, it displays:
ƒ rotateOnAxis( axis, angle ) {
q1.setFromAxisAngle( axis, angle ); <-- q1 is referenced but no declaration
this.quaternion.multiply( q1 );
return this;
}
Running 'app._scene.scene.children[0].rotateOnAxis.q1' results in:
undefined.
Lastly, evaluating 'app._scene.scene.children[0].rotateOnAxis.prototype' gives us:
{constructor: ƒ}
+ constructor:ƒ rotateOnAxis( axis, angle )
| ... (ignored here)
| [[Scopes]]:Scopes[3]
---+ 0:Closure {type: "closure", name: "", object: {…}}
|--+ q1:Quaternion {_x: 0, _y: 0, _z: 0, _w: 1} <-- scope search here
| 1:Closure {type: "closure", name: "", object: {…}}
| 2:Global {type: "global", name: "", object: Window}
It is evident from the above that there is a 3-layer stacking closure frame attached to the rotateOnAxis function's prototype.constructor property. It is also important to note that the variable (q1) saved in the closure will change whenever the outer function is invoked, necessitating a reset in its content within the setFromAxisAngle interface.