Private variables in inherited prototypes

后端 未结 4 1129
温柔的废话
温柔的废话 2020-12-05 00:54

I think I have misunderstood how Javascript prototypal inheritance works. Specifically, the prototypes internal variables seem to be shared between multiple different sub-ob

4条回答
  •  庸人自扰
    2020-12-05 01:32

    You need to forget the idea of classes. There isn't really such a thing in JavaScript as an 'instance of B'. There is only 'some object you obtained by calling the constructor function B'. An object has properties. Some are its "own" properties, others are included by searching the prototype chain.

    When you say new A, you're creating one object. Then you assign it as the prototype for B, which means that every call to new B produces a new object that has the same direct prototype, and hence the same counter variable.

    In Tim Down's answer, two alternatives are shown. His incrementPublic uses inheritance, but makes the counter variable public (i.e. gives up encapsulation). Whereas incrementInternal makes the counter private but succeeds by moving the code into B (i.e. gives up inheritance).

    What you want is a combination of three things:

    • inheritable behaviour - so it must be defined in A and require no code in B aside from setting the prototype
    • private data, stored in closure-local variables
    • per-instance data, stored in this.

    The problem is the contradiction between the last two. I would also say that inheritance is of limited value in JS anyway. It's better to treat it as a functional language:

    // higher-order function, returns another function with counter state
    var makeCounter = function() {
      var c = 0;
      return function() { return ++c; };
    };
    
    // make an object with an 'increment' method:
    var incrementable = {
      increment: makeCounter()
    };
    

    Personally I tend to avoid constructor functions and prototype inheritance most of the time. They are far less useful in JS than people from an OO background assume.

    Update I'd be wary of the statement you quoted in your update:

    Private variables only work really well with singleton objects in JavaScript.

    That's not really true. An object is just a 'dictionary' of properties, any of which may be functions. So forget objects and think about functions. You can create multiple instances of a function according to some pattern, by writing a function that returns a function. The makeCounter example about is just a simple example of this. makeCounter is not a "singleton object" and doesn't have to be limited to use in singleton objects.

提交回复
热议问题