Search code examples
javascriptclassoophoisting

Is there a standard way for Javascript classes to refer to each other?


I was wondering, is there a standard way for class properties and methods to refer to each other in their declaration? For example:

class A {
  methodA(){
    b.methodB()
    ...
  }
}

class B {
  methodB(){...}
}

const a = new A();
const b = new B(); 

///will throw ReferenceError: Cannot access 'b' before initialization;

I understand that you can add methodA in later after all class/object declarations, but it gets quite untidy after many repetitions, which I feel like defeats the purpose of classes. Or that you can delay the reference through some other means. Is there a standard way to do this?


Solution

  • First, Javascript has no "classes". The class keyword is just there to make it look familiar. It should have been proto instead of class.

    It's better to use mixins. Also it very much depends on whether to be able to propagate changes to methodB to all decedents of A, or if you want that.

    See also "prose-like syntax"

    No propagation - copying

    If you don't need propagation and you need to copy a lot of methods over:

    const A = {
        name: 'I am A.'
    }
    
    const B = {
        name: 'I am B.', // this will overwrite A when we #assign. so be careful to assign it back
        methodB() {
            console.log(`${this.name} - foo`)
        }
    }
    
    const a = Object.create(A)
    
    Object.assign(a, B)
    a.name = A.name
    
    // methodB is changed but it won't propagate.
    B.methodB = function() {
        console.log(`${this.name} - bar`)
    }
    
    a.methodB() // I am A. - foo
    B.methodB() // I am B. - bar
    

    With propagation.

    And if you only need 1 or a few methods:

    const A = {
        name: 'I am A.'
    }
    
    const B = {
        name: 'I am B.',
        methodB() {
            console.log(`${this.name} - foo`)
        }
    }
    
    const a = Object.create(A)
    
    a.methodA = function() {
        B.methodB.call(this)
    }
    
    B.methodB = function() {
        console.log(`${this.name} - bar`)
    }
    
    a.methodA() // I am A. - bar
    B.methodB() // I am B. - bar