How to Create Protected Object Properties in JavaScript

前端 未结 8 1937
梦毁少年i
梦毁少年i 2020-12-10 04:49

Is there a JavaScript pattern which mimics \"Protected\" object properties like what you see in languages like C++ ??

Basically, I\'d like to create an Object A whic

相关标签:
8条回答
  • There is no object property that can only be accessed from prototyped methods of A and not from non-prototyped methods of A. The language doesn't have that type of feature and I'm not aware of any work-around/hack to implement it.

    Using Doug Crockford's methods, you can create member properties that can only be accessed from predefined non-prototyped methods (those defined in the constructor). So, if you're trying to limit access only to a predefined set of methods, this will accomplish that. Other than that, I think you're out of luck.

    If you want other ideas, you'd probably get more help if you describe more about what you're actually trying to accomplish in your code rather than just how to emulate a feature in another language. Javascript is so much different than C++ that it's better to start from the needs of the problem rather than try to find an analogy to some C++ feature.

    0 讨论(0)
  • 2020-12-10 05:14

    There is a pattern that I have come to like that does not work the same way as protected access does in most languages, but provides a similar benefit.

    Basically, use a builder method to create a closure for properties, and then have that method create a "full" object with liberal access as well as an "exposed" object with more limited access. Place the exposed object into a property of the full object, and return that full object to the caller.

    The caller can then make use of the full object (and pass that to other appropriate collaborators), but provide only the exposed object to collaborators that should have the more restricted access.

    A contrived example…

    // Ring employs a typical private/public pattern while
    // RingEntry employs a private/exposed/full access pattern.
    
    function buildRing( size ) {
      var i
        , head = buildRingEntry( 0 )
        , newEntry;
      ;
      head.setNext( head );
      for( i = size - 1; i ; i-- ) {
        newEntry = buildRingEntry( i );
        newEntry.setNext( head.getNext() );
        head.setNext( newEntry );
      }
      function getHead() { return head.exposed; }
      return {
          getHead : getHead
      }
    }
    
    function buildRingEntry( index ) {
      var next
        , exposed
      ;
      function getIndex() { return index; }
      function setNext( newNext ) { next = newNext; }
      function getNextFullEntry() { return next; }
      function getNextExposedEntry() { return next.exposed; }
      exposed = {
          getIndex : getIndex
        , getNext  : getNextExposedEntry
      };
      return {
          getIndex : getIndex
        , setNext  : setNext
        , getNext  : getNextFullEntry
        , exposed  : exposed
      };
    }
    

    If we use that to build a ring of 4 entries ring = buildRing(4);, then ring.getHead().getIndex() gives us 0, ring.getHead().getNext().getIndex() gives us 1, ring.getHead().getNext().getNext().getIndex() gives us 2, etc.

    If we try to execute ring.getHead().setNext({}) or ring.getHead().getNext().setNext({}), however, we get an error because setNext is not a property of an exposed entry object.

    Caveat:

    Since this is in the family of patterns that build the methods again in a new closure for each new object, it is not suitable for situations in which a very high volume of instantiation may be needed.

    0 讨论(0)
  • 2020-12-10 05:20
    function ClassA(init)
    {
        var protected = {};
        protected.prop = init * 10;
        if(this.constructor != ClassA) { return protected; }
    }
    
    function ClassB()
    {
        var protected = ClassA.call(this, 5); //console.log(protected.prop);
    }
    
    //var a = new ClassA(123);
    //var b = new ClassB();
    
    0 讨论(0)
  • 2020-12-10 05:21

    You cannot do it in Javascript.

    0 讨论(0)
  • 2020-12-10 05:25

    This is probably what you're looking for: http://javascript.crockford.com/private.html

    0 讨论(0)
  • 2020-12-10 05:25

    I was interested to find a way to answer your question, and here's what I was able to do.

    You'll need this helper:

    var ProtectedHandler = (function () {
        /// <Sumarry>
        /// Tool to handle the protected members of each inheritance.
        /// </Summary>
        /// <param name="current">Current protected variable.</param>
        /// <param name="args">The arguments variable of the object.</param>
        /// <param name="callback">The function to initialise the variable in the 'object'.</param>
        /// <param name="isParent">Is this the ultimate base object.</param>
        function ProtectedHandler(current, args, callback, isParent) {
            this.child = getChild(args);
            if (callback)
                this.callback = callback;
    
            if (isParent)
                this.overrideChild(current);
        }
    
        // Get the ProtectedHandler from the arguments
        var getChild = function (args) {
            var child = null;
            if (args.length > 0 && (child = args[args.length - 1]) && child.constructor === ProtectedHandler)
                return child;
        };
    
        // Chain Initialise the protected variable of the object and its inheritances.
        ProtectedHandler.prototype.overrideChild = function (newValue) {
            if (this.callback != null) {
                this.callback(newValue);
            }
            if (this.child != null) {
                this.child.overrideChild(newValue);
            }
        };
    
        // Static function to create a new instance of the protectedHandler object.
        ProtectedHandler.handle = function (protected, arguments, callback, isParent) {
            return new ProtectedHandler(protected, arguments, callback, isParent);
        };
    
        return ProtectedHandler;
    })();
    

    This helper will allow you to handle multiple inheritances. The trick is to copy the protected variable from the base object to your new object (child).

    To prove you it's working, here's an example:

    // That's the default extends function from typescript (ref: http://www.typescriptlang.org/)
    var __extends = this.__extends || function (d, b) {
        for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
        function __() { this.constructor = d; }
        __.prototype = b.prototype;
        d.prototype = new __();
    };
    
    var BaseClass = (function () {        
        function BaseClass() {
            // Members
            var private = {},
                protected = {},
                public = this;
    
            // Constructor
            ProtectedHandler.handle(protected, arguments, function () {
                protected.type = "BaseClass";
            }, true);
    
            // Methods
            protected.saySomething = function () {
                return "Hello World";
            };
    
            public.getType = function () {
                return protected.type;
            };
        }
    
        return BaseClass;
    })();
    
    
    
    var Person = (function (_super) {
        __extends(Person, _super);
    
        function Person(name) {
            // Members
            var private = {},
                protected = {},
                public;
    
            // Constructor
            _super.call(public = this, ProtectedHandler.handle(protected, arguments, function (p) {
                protected = p; //This is required to copy the object from its base object.
                protected.name = name;
                protected.type = "Person";
            }));
    
            //Method
            public.getName = function () {
                return protected.name;
            };
    
            public.saySomething = function () {
                return protected.saySomething();
            };
        }
        return Person;
    })(BaseClass);
    
    
    var Child = (function (_super) {
        __extends(Child, _super);
    
        function Child(name) {
            // Members
            var private = {},
                protected = {},
                public;
    
            // Constructor
            _super.call(public = this, name, ProtectedHandler.handle(protected, arguments, function (p) {
                protected = p; //This is required to copy the object from its base object.
                protected.type = "Child";
            }));
    
            //Method
            public.setName = function (value) {
                return protected.name = value;
            };
        }
        return Child;
    })(Person);
    

    And here's the tests:

    var testBase = new BaseClass();
    testBase.getType(); //"BaseClass"
    testBase.saySomething; //undefined
    
    var testPerson = new Person("Nic");
    testPerson.getType(); //"Person"
    testPerson.saySomething(); //"Hello World"
    testPerson.name; //undefined
    testPerson.getName() //"Nic"
    testPerson.setName; //undefined
    
    var testChild = new Child("Bob");
    testChild.getType(); //"Child"
    testChild.saySomething(); //"Hello World"
    testChild.name; //undefined
    testChild.getName(); //"Bob"
    testChild.setName("George");
    testChild.getName(); //"George"
    
    0 讨论(0)
提交回复
热议问题