要创建一个带有公共方法的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对象。
以下是迄今为止我最喜欢的关于javascript中的私有/公共方法/成员和实例化:
这是文章:http://www.sefol.com/?p=1090
下面是一个例子:
var Person = (function () {
//Immediately returns an anonymous function which builds our modules
return function (name, location) {
alert("createPerson called with " + name);
var localPrivateVar = name;
var localPublicVar = "A public variable";
var localPublicFunction = function () {
alert("PUBLIC Func called, private var is :" + localPrivateVar)
};
var localPrivateFunction = function () {
alert("PRIVATE Func called ")
};
var setName = function (name) {
localPrivateVar = name;
}
return {
publicVar: localPublicVar,
location: location,
publicFunction: localPublicFunction,
setName: setName
}
}
})();
//Request a Person instance - should print "createPerson called with ben"
var x = Person("ben", "germany");
//Request a Person instance - should print "createPerson called with candide"
var y = Person("candide", "belgium");
//Prints "ben"
x.publicFunction();
//Prints "candide"
y.publicFunction();
//Now call a public function which sets the value of a private variable in the x instance
x.setName("Ben 2");
//Shouldn't have changed this : prints "candide"
y.publicFunction();
//Should have changed this : prints "Ben 2"
x.publicFunction();
JSFiddle: http://jsfiddle.net/northkildonan/kopj3dt3/1/
在这些情况下,当你有一个公共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