我试图创建一个尽可能隐藏对象私有属性的函数。我会在这里将私有属性定义为以下划线开头的属性,例如。 _password
。
以下是我迄今为止所得到的内容(感谢Nicolas Bevacqua's great intro to proxies)。
现在我想知道:
Reflect
方法与代理结合使用的正确方法吗?我甚至在这里需要它们吗?到目前为止我的功能:
function privatize(obj, prefix = '_', throwError = false) {
const proxyHandler = {
get(target, key) {
return private(key, 'get') ? undefined : Reflect.get(target, key);
},
set(target, key, value) {
return private(key, 'set') ? undefined : Reflect.set(target, key, value);
},
has(target, key) {
return private(key, 'has') ? false : Reflect.has(target, key);
},
deleteProperty(target, key) {
return private(key, 'delete') ? false : Reflect.deleteProperty(target, key);
},
defineProperty(target, key, descriptor) {
return private(key, 'defineProperty') ? false : Reflect.defineProperty(target, key, descriptor);
},
enumerate(target) {
return Object.keys().filter((key) => {
return !private(key, null, false);
})[Symbol.iterator]();
},
ownKeys(target) {
return Reflect.ownKeys(target).filter((key) => {
return !private(key, null, false);
});
},
getOwnPropertyDescriptor(target, key) {
return private(key, 'getOwnPropertyDescriptor') ? false : Reflect.getOwnPropertyDescriptor(target, key);
}
};
function private(key, operationName) {
if (key.indexOf(prefix) === 0) {
if (throwError) {
throw new Error(`Operation '${operationName}' is not allowed on private properties.`);
}
return true;
}
}
return new Proxy(obj, proxyHandler);
}
var o = {
first: 'should work',
_second: 'should fail'
};
var proxied = privatize(o);
console.log(proxied);
PS:对于本机浏览器支持,您可能需要在MS Edge或Firefox Dev Edition中查看它。
答案 0 :(得分:1)
您的代码存在一些问题:
throwError = throwError
函数参数中的private
部分是多余的(实际上甚至不起作用,至少在最新的Chrome中),因为throwError
将在功能无论如何。getOwnPropertyDescriptor
陷阱永远不会返回false
。对于不存在的属性,它应返回undefined
。enumerate
trap已过时。Reflect.preventExtensions()
对象上调用proxied
会破坏它。您应该通过添加preventExtensions
trap并在其中返回false
来防止阻止对象的扩展。答案 1 :(得分:1)
您需要了解"不变量"的概念。例如,如果对象是不可扩展的,则不允许通过代理隐藏其属性,并且可能不会隐藏不可配置的属性。你不能defineProperty
一个它还没有的财产。 getOwnPropertyDescriptor
必须返回一个对象或undefined
。 deleteProperty
无法删除不可配置的属性。 set
无法更改不可写,不可配置的属性。任何或所有这些都可能导致您的代码在各种情况下失败(通过在运行时抛出)。
其他小问题包括set
应该返回布尔值(成功/失败)这一事实,尽管我不确定您将返回的undefined
会发生什么。