要创建一个带有公共方法的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的文章几次,但它似乎不像“私有”方法可以被公共方法调用,而“特权”方法可以被外部调用。
老问题,但这是一个相当简单的任务,可以用核心JS正确解决…没有ES6的Class抽象。事实上,据我所知,类抽象甚至不能解决这个问题。
我们既可以使用老的构造函数,也可以使用Object.create()更好地完成这项工作。让我们先从构造函数开始。这本质上是一个与georgebrock的答案相似的解决方案,georgebrock的答案受到了批评,因为所有由Restaurant构造函数创建的餐厅都将具有相同的私有方法。我会努力克服这个限制。
function restaurantFactory(name,menu){
function Restaurant(name){
this.name = name;
}
function prototypeFactory(menu){
// This is a private function
function calculateBill(item){
return menu[item] || 0;
}
// This is the prototype to be
return { constructor: Restaurant
, askBill : function(...items){
var cost = items.reduce((total,item) => total + calculateBill(item) ,0)
return "Thank you for dining at " + this.name + ". Total is: " + cost + "\n"
}
, callWaiter : function(){
return "I have just called the waiter at " + this.name + "\n";
}
}
}
Restaurant.prototype = prototypeFactory(menu);
return new Restaurant(name,menu);
}
var menu = { water: 1
, coke : 2
, beer : 3
, beef : 15
, rice : 2
},
name = "Silver Scooop",
rest = restaurantFactory(name,menu);
console.log(rest.callWaiter());
console.log(rest.askBill("beer", "beef"));
现在显然我们不能从外部访问菜单,但我们可以很容易地重命名餐厅的name属性。
这也可以用object .create()来完成,在这种情况下,我们跳过构造函数,简单地像var rest = object .create(prototypeFactory(menu))那样做,然后像rest.name = name那样将name属性添加到rest对象。
一个丑陋但有效的解决方案:
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());
var TestClass = function( ) {
var privateProperty = 42;
function privateMethod( ) {
alert( "privateMethod, " + privateProperty );
}
this.public = {
constructor: TestClass,
publicProperty: 88,
publicMethod: function( ) {
alert( "publicMethod" );
privateMethod( );
}
};
};
TestClass.prototype = new TestClass( ).public;
var myTestClass = new TestClass( );
alert( myTestClass.publicProperty );
myTestClass.publicMethod( );
alert( myTestClass.privateMethod || "no privateMethod" );
类似于georgebrock,但不太啰嗦(恕我直言)
这样做有什么问题吗?(我哪儿都没见过)
编辑:我意识到这有点没用,因为每个独立的实例化都有自己的公共方法副本,从而破坏了原型的使用。