简体   繁体   中英

OOP Javascript: Should Private Functions Be Added to Class Prototype?

Background

I've been working with OOP style Javascript for the past few months, starting with just dissecting open source libraries. It seems like they mostly follow the same pattern, except that I've seen two ways of handling private functions, and I'm wondering which is the best (best as in best practice, or better for reasons I might not know about).

Example Code

Below is a very stripped down skeleton of the pattern I'm using. If you'll note, there are two different forms of private functions.

The first is attached to the prototype like public functions, but is prefixed with an _ .

The second is just a function who's scope is only accessible by the class.

(function(window) {

    window.FooBarClass = (function() {

        var Class = function( params ) {

            this._init( params );

        }

        /***************************************/
        /************* INITIALIZE **************/
        /***************************************/

        Class.prototype._init = function( params ) {

            // DO SETUP STUFF

        };

        /***************************************/
        /********** PUBLIC FUNCTIONS ***********/
        /***************************************/

        Class.prototype.doThings = function() {

            // DO STUFF

        };

        /***************************************/
        /****** PRIVATE FUNCTIONS 1ST WAY ******/
        /***************************************/

        Class.prototype._createSection = function( params ) {

            // DO STUFF

        };

        /***************************************/
        /****** PRIVATE FUNCTIONS 2ND WAY ******/
        /***************************************/

        function correctTwoDigitYear( variable ) {

            // DO STUFF

        }

        return Class;

    }());

}(window));

Question

Which of these is preferable, and why?

JS doesn't actually have private methods, though as you've seen you can limit access to functions and variables by closing over their scope.

In the end, if it's on the prototype, it's not private--regardless of naming convention (leading underscores, etc). So if you really want to limit access to something, do NOT put it on the prototype.

The second pattern, putting functions in the local scope, is preferable because it's actually private. It's not really OOP though.

The first pattern, putting functions in underscored properties on the prototype, is preferable because they are actual methods that get their this passed implicitly like you expect of a method. By being instance methods, they are available to any module that needs them, instead of being restricted by scope, which can be beneficial in larger projects. And of course methods are important in OOP as they offer dynamic dispatch if you want to use polymorphism.

Also prototype methods are (were?) a bit better optimised, so they were chosen if you need to squeeze out the last bit of performance, though in practice you won't see much difference to a plain function call.

any method that is attached to the prototype property of a function is accessible by the object or by the child class. SO,

class.prototype.__init

cannot be considered as a private method. It can be accesible by the object or it can be modified by extending the class ex:

var someClass = (function () {
    var Class = function( params ) {
        this._init( params );
    }

    Class.prototype._init = function( params ) {
        console.log("Hello World");
    };  
    return Class;
} ());


var extendSomeClass = someClass;

extendSomeClass.prototype._init = function () {
   console.log("Hey there");
} 

var obj = new extendSomeClass(); // this wil print "Hey there"

In the example that you have posted, the _init is acting as a constructor, hence the property associated with it is made public (though the naming convention suggests a private member). But to follow a private access, a closure scope should be the best practice. example:

var fooClass = (function () {
  var Class = function () {
    if(this._init) {
      this._init.apply(this, arguments);
    }
  }


  Class.prototype.hello = function () {
    log("hello world");
  }

  function log(args) {
    console.log(args);
  }
}());

In the example above the function log is a private method and cannot be modified/overridden outside the scope.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM