Accessing private member variables from prototype-defined functions

前端 未结 25 1239
孤城傲影
孤城傲影 2020-11-22 14:48

Is there any way to make “private” variables (those defined in the constructor), available to prototype-defined methods?

TestClass = function(){
    var priv         


        
25条回答
  •  一整个雨季
    2020-11-22 15:23

    In current JavaScript, I'm fairly certain that there is one and only one way to have private state, accessible from prototype functions, without adding anything public to this. The answer is to use the "weak map" pattern.

    To sum it up: The Person class has a single weak map, where the keys are the instances of Person, and the values are plain objects that are used for private storage.

    Here is a fully functional example: (play at http://jsfiddle.net/ScottRippey/BLNVr/)

    var Person = (function() {
        var _ = weakMap();
        // Now, _(this) returns an object, used for private storage.
        var Person = function(first, last) {
            // Assign private storage:
            _(this).firstName = first;
            _(this).lastName = last;
        }
        Person.prototype = {
            fullName: function() {
                // Retrieve private storage:
                return _(this).firstName + _(this).lastName;
            },
            firstName: function() {
                return _(this).firstName;
            },
            destroy: function() {
                // Free up the private storage:
                _(this, true);
            }
        };
        return Person;
    })();
    
    function weakMap() {
        var instances=[], values=[];
        return function(instance, destroy) {
            var index = instances.indexOf(instance);
            if (destroy) {
                // Delete the private state:
                instances.splice(index, 1);
                return values.splice(index, 1)[0];
            } else if (index === -1) {
                // Create the private state:
                instances.push(instance);
                values.push({});
                return values[values.length - 1];
            } else {
                // Return the private state:
                return values[index];
            }
        };
    }
    

    Like I said, this is really the only way to achieve all 3 parts.

    There are two caveats, however. First, this costs performance -- every time you access the private data, it's an O(n) operation, where n is the number of instances. So you won't want to do this if you have a large number of instances. Second, when you're done with an instance, you must call destroy; otherwise, the instance and the data will not be garbage collected, and you'll end up with a memory leak.

    And that's why my original answer, "You shouldn't", is something I'd like to stick to.

提交回复
热议问题