要创建一个带有公共方法的JavaScript类,我可以这样做:

function Restaurant() {}

Restaurant.prototype.buy_food = function(){
   // something here
}

Restaurant.prototype.use_restroom = function(){
   // something here
}

这样,我类的用户就可以:

var restaurant = new Restaurant();
restaurant.buy_food();
restaurant.use_restroom();

如何创建一个私有方法,可以由buy_food和use_restroom方法调用,但不能由类的用户外部调用?

换句话说,我希望我的方法实现能够做到:

Restaurant.prototype.use_restroom = function() {
   this.private_stuff();
}

但这是行不通的:

var r = new Restaurant();
r.private_stuff();

如何将private_stuff定义为私有方法,使两者都成立?

我读过Doug Crockford的文章几次,但它似乎不像“私有”方法可以被公共方法调用,而“特权”方法可以被外部调用。


当前回答

我想到了这个:编辑:实际上,有人已经链接到一个相同的解决方案。咄!

var Car = function() {
}

Car.prototype = (function() {
    var hotWire = function() {
        // Private code *with* access to public properties through 'this'
        alert( this.drive() ); // Alerts 'Vroom!'
    }

    return {
        steal: function() {
            hotWire.call( this ); // Call a private method
        },
        drive: function() {
            return 'Vroom!';
        }
    };
})();

var getAwayVechile = new Car();

hotWire(); // Not allowed
getAwayVechile.hotWire(); // Not allowed
getAwayVechile.steal(); // Alerts 'Vroom!'

其他回答

你可以这样做,但缺点是它不能成为原型的一部分:

function Restaurant() {
    var myPrivateVar;

    var private_stuff = function() {  // Only visible inside Restaurant()
        myPrivateVar = "I can set this here!";
    }

    this.use_restroom = function() {  // use_restroom is visible to all
        private_stuff();
    }

    this.buy_food = function() {   // buy_food is visible to all
        private_stuff();
    }
}

如果你想要所有的公共函数和私有函数,并让公共函数能够访问私有函数,可以这样布局一个对象的代码:

function MyObject(arg1, arg2, ...) {
  //constructor code using constructor arguments...
  //create/access public variables as 
  // this.var1 = foo;

  //private variables

  var v1;
  var v2;

  //private functions
  function privateOne() {
  }

  function privateTwon() {
  }

  //public functions

  MyObject.prototype.publicOne = function () {
  };

  MyObject.prototype.publicTwo = function () {
  };
}

一个丑陋但有效的解决方案:

function Class(cb) { const self = {}; const constructor = (fn) => { func = fn; }; const addPrivate = (fnName, obj) => { self[fnName] = obj; } const addPublic = (fnName, obj) => { this[fnName] = obj; self[fnName] = obj; func.prototype[fnName] = obj; } cb(constructor, addPrivate, addPublic, self); return func; } const test = new Class((constructor, private, public, self) => { constructor(function (test) { console.log(test) }); public('test', 'yay'); private('qwe', 'nay'); private('no', () => { return 'hello' }) public('asd', () => { return 'this is public' }) public('hello', () => { return self.qwe + self.no() + self.asd() }) }) const asd = new test('qweqwe'); console.log(asd.hello());

我已经创建了一个新工具,允许您在原型上拥有真正的私有方法 https://github.com/TremayneChrist/ProtectJS

例子:

var MyObject = (function () {

  // Create the object
  function MyObject() {}

  // Add methods to the prototype
  MyObject.prototype = {

    // This is our public method
    public: function () {
      console.log('PUBLIC method has been called');
    },

    // This is our private method, using (_)
    _private: function () {
      console.log('PRIVATE method has been called');
    }
  }

  return protect(MyObject);

})();

// Create an instance of the object
var mo = new MyObject();

// Call its methods
mo.public(); // Pass
mo._private(); // Fail

我知道这是一个老话题,但我试图找到一种方法来保持代码的“简单性”的可维护性的目的,并保持轻的内存负载。它有这样的模式。希望能有所帮助。

const PublicClass=function(priv,pub,ro){
    let _priv=new PrivateClass(priv,pub,ro);
    ['publicMethod'].forEach(k=>this[k]=(...args)=>_priv[k](...args));
    ['publicVar'].forEach(k=>Object.defineProperty(this,k,{get:()=>_priv[k],set:v=>_priv[k]=v}));
    ['readOnlyVar'].forEach(k=>Object.defineProperty(this,k,{get:()=>_priv[k]}));
};

class PrivateClass{
    constructor(priv,pub,ro){
        this.privateVar=priv;
        this.publicVar=pub;
        this.readOnlyVar=ro;
    }
    publicMethod(arg1,arg2){
        return this.privateMethod(arg1,arg2);
    }
    privateMethod(arg1,arg2){
        return arg1+''+arg2;
    }
}
// in node;
module.exports=PublicClass;
// in browser;
const PublicClass=(function(){
    // code here
    return PublicClass;
})();

同样的原则适用于老式浏览器:

var PublicClass=function(priv,pub,ro){
    var scope=this;
    var _priv=new PrivateClass(priv,pub,ro);
    ['publicMethod'].forEach(function(k){
        scope[k]=function(){return _priv[k].apply(_priv,arguments)};
    });
    ['publicVar'].forEach(function(k){
        Object.defineProperty(scope,k,{get:function(){return _priv[k]},set:function(v){_priv[k]=v}});
    });
    ['readOnlyVar'].forEach(function(k){
        Object.defineProperty(scope,k,{get:function(){return _priv[k]}});
    });
};

var PrivateClass=function(priv,pub,ro){
    this.privateVar=priv;
    this.publicVar=pub;
    this.readOnlyVar=ro;
};
PrivateClass.prototype.publicMethod=function(arg1,arg2){
    return this.privateMethod(arg1,arg2);
};
PrivateClass.prototype.privateMethod=function(arg1,arg2){
    return arg1+''+arg2;
};

为了减轻公共类的冗长和负载,将此模式应用于构造函数:

const AbstractPublicClass=function(instanciate,inherit){
    let _priv=instanciate();
    inherit.methods?.forEach(k=>this[k]=(...args)=>_priv[k](...args));
    inherit.vars?.forEach(k=>Object.defineProperty(this,k,{get:()=>_priv[k],set:v=>_priv[k]=v}));
    inherit.readonly?.forEach(k=>Object.defineProperty(this,k,{get:()=>_priv[k]}));
};

AbstractPublicClass.static=function(_pub,_priv,inherit){
    inherit.methods?.forEach(k=>_pub[k]=(...args)=>_priv[k](...args));
    inherit.vars?.forEach(k=>Object.defineProperty(_pub,k,{get:()=>_priv[k],set:v=>_priv[k]=v}));
    inherit.readonly?.forEach(k=>Object.defineProperty(_pub,k,{get:()=>_priv[k]}));
};

使用:

// PrivateClass ...
PrivateClass.staticVar='zog';
PrivateClass.staticMethod=function(){return 'hello '+this.staticVar;};


const PublicClass=function(priv,pub,ro){
    AbstractPublicClass.apply(this,[()=>new PrivateClass(priv,pub,ro),{
        methods:['publicMethod'],
        vars:['publicVar'],
        readonly:['readOnlyVar']
    }]);
};
AbstractPublicClass.static(PublicClass,PrivateClass,{
    methods:['staticMethod'],
    vars:['staticVar']
});

PS:这种方法的默认(大多数时候可以忽略不计)是,与完全公共相比,它可以占用很小的计算负载。但只要你不使用它与高度请求类应该是可以的。