您的实施中至少存在一个问题是对obj.constructor
. constructor
众所周知,该属性不是只读的,而且很容易搞砸。考虑以下模式,这是在 Javascript 中定义类的一种非常常见的方式:
function Foo() {};
Foo.prototype = {
myProperty: 1,
myFunction: function() {
return 2;
}
};
// make an instance
var foo = new Foo();
foo instanceof Foo; // true
foo.constructor == Foo; // false! The constructor is now Object
(new foo.constructor()) instanceof Foo; // false
我认为这样做的方法是以您的obj
实例为原型创建一个新类。然后,您可以通过在新类的对象上添加空键来阻止对旧功能的访问:
function getRestricted(obj, publicProperties) {
function RestrictedObject() {};
RestrictedObject.prototype = obj;
var ro = new RestrictedObject();
// add undefined keys to block access
for (var key in obj) {
// note: use _.indexOf instead -- this was just easier to test
if (publicProperties.indexOf(key) < 0) {
ro[key] = null;
} else {
// again, use _.isFunction if you prefer
if (typeof obj[key]=='function') {
(function(key) {
// wrap functions to use original scope
ro[key] = function() {
// basically the same as _.bind
return obj[key].apply(obj, arguments);
}
})(key);
}
}
}
return ro;
}
function Foo() {
var a=0;
this.getA = function() {
this.setA(a+1);
return a;
};
this.setA = function(newa) {
a = newa;
}
};
// make an instance
var foo = new Foo();
foo.setA(1);
foo.getA(); // 2
// make a restricted instance
var restrictedFoo = getRestricted(foo, ['getA']);
restrictedFoo.getA(); // 3
restrictedFoo instanceof Foo; // true
try {
restrictedFoo.setA(2); // TypeError: Property 'setA' is not a function
} catch(e) {
"not a function";
}
// one bump here:
"setA" in restrictedFoo; // true - just set to undefined
// foo is unaffected
foo.setA(4);
foo.getA(); // 5
(这部分基于 Crockford 的幂构造函数,在此处讨论。)
编辑:我更新了上面的代码以解决您的评论。它现在看起来有点类似于您的实现,但它更简单并且避免了这个constructor
问题。如您所见,公共函数中的引用现在指的是旧对象。