Accessing private member variables from prototype-defined functions

前端 未结 25 1377
孤城傲影
孤城傲影 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:43

    When I read this, it sounded like a tough challenge so I decided to figure out a way. What I came up with was CRAAAAZY but it totally works.

    First, I tried defining the class in an immediate function so you'd have access to some of the private properties of that function. This works and allows you to get some private data, however, if you try to set the private data you'll soon find that all the objects will share the same value.

    var SharedPrivateClass = (function() { // use immediate function
        // our private data
        var private = "Default";
    
        // create the constructor
        function SharedPrivateClass() {}
    
        // add to the prototype
        SharedPrivateClass.prototype.getPrivate = function() {
            // It has access to private vars from the immediate function!
            return private;
        };
    
        SharedPrivateClass.prototype.setPrivate = function(value) {
            private = value;
        };
    
        return SharedPrivateClass;
    })();
    
    var a = new SharedPrivateClass();
    console.log("a:", a.getPrivate()); // "a: Default"
    
    var b = new SharedPrivateClass();
    console.log("b:", b.getPrivate()); // "b: Default"
    
    a.setPrivate("foo"); // a Sets private to "foo"
    console.log("a:", a.getPrivate()); // "a: foo"
    console.log("b:", b.getPrivate()); // oh no, b.getPrivate() is "foo"!
    
    console.log(a.hasOwnProperty("getPrivate")); // false. belongs to the prototype
    console.log(a.private); // undefined
    
    // getPrivate() is only created once and instanceof still works
    console.log(a.getPrivate === b.getPrivate);
    console.log(a instanceof SharedPrivateClass);
    console.log(b instanceof SharedPrivateClass);

    There are plenty of cases where this would be adequate like if you wanted to have constant values like event names that get shared between instances. But essentially, they act like private static variables.

    If you absolutely need access to variables in a private namespace from within your methods defined on the prototype, you can try this pattern.

    var PrivateNamespaceClass = (function() { // immediate function
        var instance = 0, // counts the number of instances
            defaultName = "Default Name",  
            p = []; // an array of private objects
    
        // create the constructor
        function PrivateNamespaceClass() {
            // Increment the instance count and save it to the instance. 
            // This will become your key to your private space.
            this.i = instance++; 
            
            // Create a new object in the private space.
            p[this.i] = {};
            // Define properties or methods in the private space.
            p[this.i].name = defaultName;
            
            console.log("New instance " + this.i);        
        }
    
        PrivateNamespaceClass.prototype.getPrivateName = function() {
            // It has access to the private space and it's children!
            return p[this.i].name;
        };
        PrivateNamespaceClass.prototype.setPrivateName = function(value) {
            // Because you use the instance number assigned to the object (this.i)
            // as a key, the values set will not change in other instances.
            p[this.i].name = value;
            return "Set " + p[this.i].name;
        };
    
        return PrivateNamespaceClass;
    })();
    
    var a = new PrivateNamespaceClass();
    console.log(a.getPrivateName()); // Default Name
    
    var b = new PrivateNamespaceClass();
    console.log(b.getPrivateName()); // Default Name
    
    console.log(a.setPrivateName("A"));
    console.log(b.setPrivateName("B"));
    console.log(a.getPrivateName()); // A
    console.log(b.getPrivateName()); // B
    
    // private objects are not accessible outside the PrivateNamespaceClass function
    console.log(a.p);
    
    // the prototype functions are not re-created for each instance
    // and instanceof still works
    console.log(a.getPrivateName === b.getPrivateName);
    console.log(a instanceof PrivateNamespaceClass);
    console.log(b instanceof PrivateNamespaceClass);

    I'd love some feedback from anyone who sees an error with this way of doing it.

提交回复
热议问题