要创建一个带有公共方法的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的文章几次,但它似乎不像“私有”方法可以被公共方法调用,而“特权”方法可以被外部调用。


当前回答

你必须在你实际的构造函数周围放一个闭包,在那里你可以定义你的私有方法。 要通过这些私有方法改变实例的数据,你必须给它们一个"this",要么作为函数参数,要么用.apply(this)调用这个函数:

var Restaurant = (function(){
    var private_buy_food = function(that){
        that.data.soldFood = true;
    }
    var private_take_a_shit = function(){
        this.data.isdirty = true;   
    }
    // New Closure
    function restaurant()
    {
        this.data = {
            isdirty : false,
            soldFood: false,
        };
    }

    restaurant.prototype.buy_food = function()
    {
       private_buy_food(this);
    }
    restaurant.prototype.use_restroom = function()
    {
       private_take_a_shit.call(this);
    }
    return restaurant;
})()

// TEST:

var McDonalds = new Restaurant();
McDonalds.buy_food();
McDonalds.use_restroom();
console.log(McDonalds);
console.log(McDonalds.__proto__);

其他回答

我认为这样的问题一次又一次地出现是因为缺乏对闭包的理解。Сlosures是JS中最重要的东西。每个JS程序员都必须感受到它的本质。

1. 首先,我们需要创建单独的作用域(闭包)。

function () {

}

2. 在这个领域,我们想做什么就做什么。没人会知道的。

function () {
    var name,
        secretSkills = {
            pizza: function () { return new Pizza() },
            sushi: function () { return new Sushi() }
        }

    function Restaurant(_name) {
        name = _name
    }
    Restaurant.prototype.getFood = function (name) {
        return name in secretSkills ? secretSkills[name]() : null
    }
}

3.为了让全世界知道我们的餐厅班, 我们必须从闭包中返回它。

var Restaurant = (function () {
    // Restaurant definition
    return Restaurant
})()

4. 最后,我们有:

var Restaurant = (function () {
    var name,
        secretSkills = {
            pizza: function () { return new Pizza() },
            sushi: function () { return new Sushi() }
        }

    function Restaurant(_name) {
        name = _name
    }
    Restaurant.prototype.getFood = function (name) {
        return name in secretSkills ? secretSkills[name]() : null
    }
    return Restaurant
})()

5. 此外,这种方法具有继承和模板的潜力

// Abstract class
function AbstractRestaurant(skills) {
    var name
    function Restaurant(_name) {
        name = _name
    }
    Restaurant.prototype.getFood = function (name) {
        return skills && name in skills ? skills[name]() : null
    }
    return Restaurant
}

// Concrete classes
SushiRestaurant = AbstractRestaurant({ 
    sushi: function() { return new Sushi() } 
})

PizzaRestaurant = AbstractRestaurant({ 
    pizza: function() { return new Pizza() } 
})

var r1 = new SushiRestaurant('Yo! Sushi'),
    r2 = new PizzaRestaurant('Dominos Pizza')

r1.getFood('sushi')
r2.getFood('pizza')

我希望这能帮助人们更好地理解这个主题

既然每个人都在这里张贴自己的代码,我也要这样做…

我喜欢Crockford,因为他在Javascript中引入了真正的面向对象模式。但他也产生了一个新的误解,那个“那个”。

那么他为什么要用"that = this"呢?这和私人活动完全没有关系。它与内部函数有关!

因为根据Crockford的说法,这是有bug的代码:

Function Foo( ) {
    this.bar = 0; 
    var foobar=function( ) {
        alert(this.bar);
    }
} 

所以他建议这样做:

Function Foo( ) {
    this.bar = 0;
    that = this; 
    var foobar=function( ) {
        alert(that.bar);
    }
}

就像我说的,我很确定Crockford对这个和这个的解释是错误的(但他的代码肯定是正确的)。或者他只是在愚弄Javascript世界,知道谁在复制他的代码?我不知道……我不是浏览器极客

EDIT

啊,这就是问题所在:'var that = this;'在JavaScript中是什么意思?

所以Crockie的解释是错误的....但他的代码是正确的,所以他还是个好人。:))

将所有代码包装在匿名函数中:然后,所有函数将是私有的,只有函数附加到窗口对象:

(function(w,nameSpacePrivate){
     w.Person=function(name){
         this.name=name;   
         return this;
     };

     w.Person.prototype.profilePublic=function(){
          return nameSpacePrivate.profile.call(this);
     };  

     nameSpacePrivate.profile=function(){
       return 'My name is '+this.name;
     };

})(window,{});

用这个:

  var abdennour=new Person('Abdennour');
  abdennour.profilePublic();

小提琴

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

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();
    }
}

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

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