要创建一个带有公共方法的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的文章几次,但它似乎不像“私有”方法可以被公共方法调用,而“特权”方法可以被外部调用。
既然每个人都在这里张贴自己的代码,我也要这样做…
我喜欢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的解释是错误的....但他的代码是正确的,所以他还是个好人。:))
既然每个人都在这里张贴自己的代码,我也要这样做…
我喜欢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的解释是错误的....但他的代码是正确的,所以他还是个好人。:))
下面是我创建的类,用来理解Douglas Crockford在他的网站Private Members in JavaScript中的建议
function Employee(id, name) { //Constructor
//Public member variables
this.id = id;
this.name = name;
//Private member variables
var fName;
var lName;
var that = this;
//By convention, we create a private variable 'that'. This is used to
//make the object available to the private methods.
//Private function
function setFName(pfname) {
fName = pfname;
alert('setFName called');
}
//Privileged function
this.setLName = function (plName, pfname) {
lName = plName; //Has access to private variables
setFName(pfname); //Has access to private function
alert('setLName called ' + this.id); //Has access to member variables
}
//Another privileged member has access to both member variables and private variables
//Note access of this.dataOfBirth created by public member setDateOfBirth
this.toString = function () {
return 'toString called ' + this.id + ' ' + this.name + ' ' + fName + ' ' + lName + ' ' + this.dataOfBirth;
}
}
//Public function has access to member variable and can create on too but does not have access to private variable
Employee.prototype.setDateOfBirth = function (dob) {
alert('setDateOfBirth called ' + this.id);
this.dataOfBirth = dob; //Creates new public member note this is accessed by toString
//alert(fName); //Does not have access to private member
}
$(document).ready()
{
var employee = new Employee(5, 'Shyam'); //Create a new object and initialize it with constructor
employee.setLName('Bhaskar', 'Ram'); //Call privileged function
employee.setDateOfBirth('1/1/2000'); //Call public function
employee.id = 9; //Set up member value
//employee.setFName('Ram'); //can not call Private Privileged method
alert(employee.toString()); //See the changed object
}
以遵循Crockford私有或特权模式的任何解决方案为例。例如:
function Foo(x) {
var y = 5;
var bar = function() {
return y * x;
};
this.public = function(z) {
return bar() + x * z;
};
}
在任何情况下,如果攻击者在JS上下文中没有“执行”权,他就没有办法访问任何“公共”或“私有”字段或方法。如果攻击者有访问权限,他可以执行以下一行代码:
eval("Foo = " + Foo.toString().replace(
/{/, "{ this.eval = function(code) { return eval(code); }; "
));
注意,上面的代码对于所有构造函数类型-privacy都是通用的。这里的一些解决方案会失败,但应该清楚的是,几乎所有基于闭包的解决方案都可以通过不同的replace()参数像这样被破坏。
在此执行之后,任何用new Foo()创建的对象都将有一个eval方法,可以调用该方法来返回或更改构造函数闭包中定义的值或方法,例如:
f = new Foo(99);
f.eval("x");
f.eval("y");
f.eval("x = 8");
我能看到的唯一问题是,它不会工作的情况下,只有一个实例,它是在加载时创建的。但这样就没有理由真正定义原型了,在这种情况下,攻击者可以简单地重新创建对象,而不是构造函数,只要他有方法传递相同的参数(例如,它们是常量或从可用值计算出来的)。
在我看来,这使得Crockford的解决方案毫无用处。由于“隐私”很容易被打破,他的解决方案的缺点(可读性和可维护性降低,性能下降,内存增加)使得基于“无隐私”原型的方法成为更好的选择。
我通常使用前导下划线标记__private和_protected方法和字段(Perl风格),但在JavaScript中拥有隐私的想法只是表明它是一种被误解的语言。
因此,除了Crockford的第一句话外,我不同意他的观点。
那么如何在JS中获得真正的隐私呢?将所有需要私有的东西放在服务器端,并使用JS进行AJAX调用。