简体   繁体   中英

How to reference an object in many Javascript classes without passing it into every function?

In the browser there is not a gl object until you make one:

const gl = canvas.getContext('webgl2')

This means that there it is challenging to reference any of the gl properties (like gl.createBuffer or gl.ARRAY_BUFFER ) in something like a class .

In C++ these objects are included and therefore accessible without aa particular instance of gl.

How can I create a class which has a member variable whose value is set to some property of a gl object?

For instance:

class App {
  constructor () {
     this.VBO = gl.createBuffer() // gl is not defined here
  }
}

I think the most common way is to pass in a gl instance into the constructor (ie):

class App {
  constructor (gl) {
     this.VBO = gl.createBuffer() // gl is passed in
  }
}

but this seems like it would get annoying if I have to make hundreds of different calls and pass in a gl object each time.

Additionally I guess I could define some sort of global gl object: gl = canvas.getContext('webgl2') and then just assume that there is some global gl object everywhere it needs to be accessed, but this seems like a very bad idea.

I would appreciate any ideas on a good, clean design paradigm to get around these issues.

The only thing you need to do is make sure you don't execute any of your class instantiating code before you have assigned a value to gl , and then define gl in the same context as the classes. For example:

document.addEventListener('DOMContentLoaded', function() {
    class App {
        constructor () {
             this.VBO = gl.createBuffer() // gl is defined when getting here
        }
    }

    const canvas = document.getElementById('mycanvas'),
          gl = canvas.getContext('webgl2'),
          app = new App();
    // ... etc
});

If your classes are defined outside of a function context and this cannot be changed, then define gl on the global object:

class App {
    constructor () {
         this.VBO = window.gl.createBuffer() // gl is defined when getting here
    }
}

document.addEventListener('DOMContentLoaded', function() {
    var canvas = document.getElementById('mycanvas');
    window.gl = canvas.getContext('webgl2');
    var app = new App();
    // ...etc
});

I think the most common way is to pass in a gl instance into the constructor (ie):

class App {
  constructor (gl) {
     this.VBO = gl.createBuffer() // gl is passed in
  }
}

but this seems like it would get annoying if I have to make hundreds of different calls and pass in a gl object each time.

Thats the common way for good reason. Searching the scope-chain until you reach a "gl" object on global scope is much slower, especially if you call it a hundred times in different functions per frame.

It is better to pass the "gl"-object to a class and create an instance-property-reference - so you can access "this.gl" in prototype-Functions, too - without any performance-critical scope-chain-lookups outside the class.

class App {
  constructor(gl) { //pass gl
     this.gl = gl; // always create a instance-property for fast access
     this.VBO = this.gl.createBuffer(); // access methods through "this.gl"
     this.foo = new FooGL(gl); // pass "gl" to other classes
  }

  abc() {
     this.gl.doSomeThingABC(); // access methods through "this.gl"
     this.foo.doSomething(); // FooGL has his own "gl" instance-property
                             // to access methods through its own "this.gl"
  }
}
// or
App.prototype.xyz = function()
{
    return this.gl.doSomeThingXYZ(); // access methods through "this.gl"
}

const gl = document.createElement('canvas').getContext('webgl2');
const app = new App(gl);

Thats the best method for high performance, even if its more code to write. If you work with WebGL, good performance is the most important to achieve a high framerate.

Of course you can do anything else like extending classes, create singletons or access global properties. But if you want "good, clean [and performant] design", always pass the object-references and create a local property for fast access. Don't save on the wrong place.

One thing you can do to access that property inside all the instance is to assign that variable to that class's prototype.

Also you can use extends keyword to extend the properties from parent class. In the below code App and App2 use the same function fun2 from Parent protype.

 class Parent{ constructor() { this.fun = function(){ return 'An instance property ' } } } Parent.prototype.fun2 = function(){ return 'not an instance property' } class App extends Parent{ constructor () { super(); this.VBO = App.gl.createBuffer() } } App.gl = { createBuffer : function(){ console.log('from App prototype ') } } var a = new App(); console.log(a.fun()) class App2 extends Parent{ } var a2 = new App2(); console.log(a2.fun()) console.log(a2.fun2()) 

You can create a singleton, and every time you import that singleton, it will import the same gl .

// gl.js    
const gl = canvas.getContext('webgl');

export default gl;

// class1.js
import gl from './gl.js';
class App {
  constructor () {
     this.VBO = gl.createBuffer() // gl is not defined here
  }
}

// class2.js
import gl from './gl.js'; // exactly the same gl
class B {
  constructor () {
     this.VBO = gl.createBuffer() // gl is not defined here
  }
}

You can read more about singletones in this book .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM