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


当前回答

Class({  
    Namespace:ABC,  
    Name:"ClassL2",  
    Bases:[ABC.ClassTop],  
    Private:{  
        m_var:2  
    },  
    Protected:{  
        proval:2,  
        fight:Property(function(){  
            this.m_var--;  
            console.log("ClassL2::fight (m_var)" +this.m_var);  
        },[Property.Type.Virtual])  
    },  
    Public:{  
        Fight:function(){  
            console.log("ClassL2::Fight (m_var)"+this.m_var);  
            this.fight();  
        }  
    }  
});  

https://github.com/nooning/JSClass

其他回答

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

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

你可以像这样模拟私有方法:

function Restaurant() {
}

Restaurant.prototype = (function() {
    var private_stuff = function() {
        // Private code here
    };

    return {

        constructor:Restaurant,

        use_restroom:function() {
            private_stuff();
        }

    };
})();

var r = new Restaurant();

// This will work:
r.use_restroom();

// This will cause an error:
r.private_stuff();

更多关于此技术的信息,请访问:http://webreflection.blogspot.com/2008/04/natural-javascript-private-methods.html

模块模式在大多数情况下是正确的。但是如果您有数千个实例,类可以节省内存。如果需要考虑节省内存,并且您的对象包含少量私有数据,但有大量公共函数,那么您将希望所有公共函数都驻留在.prototype中以节省内存。

这是我想到的:

var MyClass = (function () {
    var secret = {}; // You can only getPriv() if you know this
    function MyClass() {
        var that = this, priv = {
            foo: 0 // ... and other private values
        };
        that.getPriv = function (proof) {
            return (proof === secret) && priv;
        };
    }
    MyClass.prototype.inc = function () {
        var priv = this.getPriv(secret);
        priv.foo += 1;
        return priv.foo;
    };
    return MyClass;
}());
var x = new MyClass();
x.inc(); // 1
x.inc(); // 2

对象priv包含私有属性。它可以通过公共函数getPriv()访问,但该函数返回false,除非您将secret传递给它,并且只有在主闭包中才知道。

就我个人而言,我更喜欢用JavaScript创建类的以下模式:

var myClass = (function() {
    // Private class properties go here

    var blueprint = function() {
        // Private instance properties go here
        ...
    };

    blueprint.prototype = { 
        // Public class properties go here
        ...
    };

    return  {
         // Public class properties go here
        create : function() { return new blueprint(); }
        ...
    };
})();

如您所见,它允许您定义类属性和实例属性,每个属性都可以是公共的和私有的。


Demo

var Restaurant = function() { var totalfoodcount = 0; // Private class property var totalrestroomcount = 0; // Private class property var Restaurant = function(name){ var foodcount = 0; // Private instance property var restroomcount = 0; // Private instance property this.name = name this.incrementFoodCount = function() { foodcount++; totalfoodcount++; this.printStatus(); }; this.incrementRestroomCount = function() { restroomcount++; totalrestroomcount++; this.printStatus(); }; this.getRestroomCount = function() { return restroomcount; }, this.getFoodCount = function() { return foodcount; } }; Restaurant.prototype = { name : '', buy_food : function(){ this.incrementFoodCount(); }, use_restroom : function(){ this.incrementRestroomCount(); }, getTotalRestroomCount : function() { return totalrestroomcount; }, getTotalFoodCount : function() { return totalfoodcount; }, printStatus : function() { document.body.innerHTML += '<h3>Buying food at '+this.name+'</h3>' + '<ul>' + '<li>Restroom count at ' + this.name + ' : '+ this.getRestroomCount() + '</li>' + '<li>Food count at ' + this.name + ' : ' + this.getFoodCount() + '</li>' + '<li>Total restroom count : '+ this.getTotalRestroomCount() + '</li>' + '<li>Total food count : '+ this.getTotalFoodCount() + '</li>' + '</ul>'; } }; return { // Singleton public properties create : function(name) { return new Restaurant(name); }, printStatus : function() { document.body.innerHTML += '<hr />' + '<h3>Overview</h3>' + '<ul>' + '<li>Total restroom count : '+ Restaurant.prototype.getTotalRestroomCount() + '</li>' + '<li>Total food count : '+ Restaurant.prototype.getTotalFoodCount() + '</li>' + '</ul>' + '<hr />'; } }; }(); var Wendys = Restaurant.create("Wendy's"); var McDonalds = Restaurant.create("McDonald's"); var KFC = Restaurant.create("KFC"); var BurgerKing = Restaurant.create("Burger King"); Restaurant.printStatus(); Wendys.buy_food(); Wendys.use_restroom(); KFC.use_restroom(); KFC.use_restroom(); Wendys.use_restroom(); McDonalds.buy_food(); BurgerKing.buy_food(); Restaurant.printStatus(); BurgerKing.buy_food(); Wendys.use_restroom(); McDonalds.buy_food(); KFC.buy_food(); Wendys.buy_food(); BurgerKing.buy_food(); McDonalds.buy_food(); Restaurant.printStatus();

看看这小提琴。