要创建一个带有公共方法的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 Restaurant = (function() {

 var _id = 0;
 var privateVars = [];

 function Restaurant(name) {
     this.id = ++_id;
     this.name = name;
     privateVars[this.id] = {
         cooked: []
     };
 }

 Restaurant.prototype.cook = function (food) {
     privateVars[this.id].cooked.push(food);
 }

 return Restaurant;

})();

在直接函数的作用域之外查找私有变量是不可能的。 没有重复的函数,节省内存。

缺点是私有变量的查找非常笨拙。“煮熟了”这个词很可笑。还有一个额外的“id”变量。

其他回答

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

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!'

在这些情况下,当你有一个公共API,并且你想要私有和公共的方法/属性时,我总是使用模块模式。这个模式在YUI库中很流行,详细信息可以在这里找到:

http://yuiblog.com/blog/2007/06/12/module-pattern/

它非常简单明了,其他开发人员也很容易理解。举个简单的例子:

var MYLIB = function() {  
    var aPrivateProperty = true;
    var aPrivateMethod = function() {
        // some code here...
    };
    return {
        aPublicMethod : function() {
            aPrivateMethod(); // okay
            // some code here...
        },
        aPublicProperty : true
    };  
}();

MYLIB.aPrivateMethod() // not okay
MYLIB.aPublicMethod() // okay

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

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

ES12私有方法

现在你可以使用es12私有方法来实现这一点。您只需要在方法名之前添加一个#。

class ClassWithPrivateMethod {
  #privateMethod() {
    return 'hello world';
  }

  getPrivateMessage() {
    return #privateMethod();
  }
}

我更喜欢将私有数据存储在关联的WeakMap中。这允许你将你的公共方法保留在原型上。对于大量的对象,这似乎是处理这个问题的最有效的方法。

const data = new WeakMap();

function Foo(value) {
    data.set(this, {value});
}

// public method accessing private value
Foo.prototype.accessValue = function() {
    return data.get(this).value;
}

// private 'method' accessing private value
function accessValue(foo) {
    return data.get(foo).value;
}

export {Foo};