【发布时间】:2014-10-04 16:21:08
【问题描述】:
背景
我决定通过在 JS 中制作一个简单的计算器应用程序来练习。第一步是实现一个堆栈类。然而,我在使用显示原型模式(?)实现数据封装时遇到了一些问题。这是它现在的样子:
堆栈“类”:
var Stack = (function () {
var Stack = function() {
this.arr = []; // accessible to prototype methods but also to public
};
Stack.prototype = Object.prototype; // inherits from Object
Stack.prototype.push = function(x) {
this.arr.push(x);
};
Stack.prototype.pop = function() {
return this.arr.length ? (this.arr.splice(this.arr.length - 1, 1))[0] : null;
};
Stack.prototype.size = function() {
return this.arr.length;
};
Stack.prototype.empty = function() {
return this.arr.length === 0;
};
return Stack;
})();
测试代码:
var s1 = new Stack();
var s2 = new Stack();
for(var j = 1, k = 2; j < 10, k < 11; j++, k++) {
s1.push(3*j);
s2.push(4*k);
}
console.log("s1:");
while(!s1.empty()) console.log(s1.pop());
console.log("s2:");
while(!s2.empty()) console.log(s2.pop());
问题
唯一的问题是arr 是可访问的。我想以某种方式隐藏arr 变量。
解决方案的尝试
我的第一个想法是把它变成一个私有变量,比如Stack:
var Stack = (function () {
var arr = []; // private, but shared by all instances
var Stack = function() { };
Stack.prototype = Object.prototype;
Stack.prototype.push = function(x) {
arr.push(x);
};
// etc.
})();
但是这种方法当然行不通,因为arr 变量是共享每个实例的。所以这是制作私有 class 变量而不是私有实例变量的好方法。
我想到的第二种方式(这真的很疯狂,而且绝对不利于可读性)是使用随机数来限制对数组变量的访问,几乎就像密码一样:
var Stack = (function() {
var pass = String(Math.floor(Math.pow(10, 15 * Math.random()));
var arrKey = "arr" + pass;
var Stack = function() {
this[arrKey] = []; // private instance and accessible to prototypes, but too dirty
};
Stack.prototype = Object.prototype;
Stack.prototype.push = function(x) {
this[arrKey].push(x);
};
// etc.
})();
这个解决方案……很有趣。但显然不是我想做的。
最后一个想法,也就是 Crockford does,允许我创建一个私有实例成员,但我无法告诉它让我定义的公共原型方法可见。
var Stack = (function() {
var Stack = function() {
var arr = []; // private instance member but not accessible to public methods
this.push = function(x) { arr.push(x); }; // see note [1]
}
})();
[1] 这几乎就在那里,但我不想在var Stack = function() {...} 中包含函数定义,因为每次创建实例时都会重新创建它们。一个聪明的 JS 编译器会意识到它们不依赖任何条件并缓存函数代码,而不是一遍又一遍地重新创建 this.push,但如果可以避免的话,我宁愿不依赖推测性缓存。
问题
有没有办法创建一个原型方法可以访问的私有实例成员?通过某种方式利用封闭匿名函数创建的“影响力泡沫”?
【问题讨论】:
-
请注意,Douglas Crockford 考虑使用
})();狗球,并在将函数包装在括号中时推荐使用}());。 youtube.com/watch?v=eGArABpLy0k -
你不能不为每个特权函数的每个实例创建一个闭包。这是一种代码更多但闭包更少的 protected 模式:stackoverflow.com/questions/21799353/…
-
@HMR 我现在看到我下面的新答案与您链接的答案基本相同。很遗憾,您第一次发帖时我没听懂(本可以为自己节省一些时间!)。
标签: javascript prototype private-members