我想创建一个具有隐藏属性的对象(一个不在for (var x in obj循环中显示的属性).是否有可能做到这一点?
Tim*_*own 44
在ECMAScript 3中是不可能的(这是主要的浏览器在2010年提出这个问题时实现的).但是,在ECMAScript 5中,所有主流浏览器的当前版本都可以实现,可以将属性设置为不可枚举:
var obj = {
name: "Fred"
};
Object.defineProperty(obj, "age", {
enumerable: false,
writable: true
});
obj.age = 75;
/* The following will only log "name=>Fred" */
for (var i in obj) {
console.log(i + "=>" + obj[i]);
}
Run Code Online (Sandbox Code Playgroud)
这适用于当前浏览器:有关旧版浏览器兼容性的详细信息,请参阅http://kangax.github.com/es5-compat-table/.
请注意,该属性也必须在调用中设置为可写,Object.defineProperty以允许正常分配(false默认情况下).
这有点棘手!
function secret() {
var cache = {};
return function(){
if (arguments.length == 1) { return cache[arguments[0]];}
if (arguments.length == 2) { cache[arguments[0]] = arguments[1]; }
};
}
var a = secret();
a.hello = 'world';
a('hidden', 'from the world');
Run Code Online (Sandbox Code Playgroud)
如果你是一个真正的专业人士,你可以这样做!
var a = new (secret())();
a.hello = 'world';
a.constructor('hidden', 'from the world');
Run Code Online (Sandbox Code Playgroud)
现在,如果你看一个萤火虫它将是一个对象...但你知道更好!;-)
为了保持最新状态,这就是ES6 +中的状态.我有点超出问题的范围,并讨论如何隐藏属性,而不仅仅是for ... in循环.
有几种方法可以创建可能被称为"隐藏属性"的东西,而不会查看由闭包关闭的变量,这些变量受到作用域规则的限制.
与以前版本的ECMAScript一样,您可以使用Object.defineProperty创建未标记的属性enumerable.当您使用某些方法(例如for ... in循环和Object.keys函数)枚举对象的属性时,这会使属性不显示.
Object.defineProperty(myObject, "meaning of life", {
enumerable : false,
value : 42
});
Run Code Online (Sandbox Code Playgroud)
但是,您仍然可以使用该Object.getOwnPropertyNames函数找到它,该函数甚至返回不可枚举的属性.当然,你仍然可以通过它的密钥访问该属性,理论上它只是一个任何人都可以构建的字符串.
symbol财产在ES6中,可以使用新原始类型的键创建属性 - symbol.Javascript本身使用此类型来使用for ... of循环和库编写器枚举对象以执行各种其他操作.
Symbols有一个描述性文本,但它们是具有唯一标识的引用类型.它们不像字符串,如果它们具有相同的值则相等.要使两个符号相等,它们必须是两个完全相同的引用.
您创建一个symbol使用该Symbol功能:
let symb = Symbol("descriptive text");
Run Code Online (Sandbox Code Playgroud)
您可以使用该Object.defineProperty函数定义符号作为键的属性.
let theSecretKey = Symbol("meaning of life");
Object.defineProperty(myObject, theSecretKey, {
enumerable : false,
value : 42
});
Run Code Online (Sandbox Code Playgroud)
除非有人获得对该确切符号对象的引用,否则它们无法按键查找属性的值.
但您也可以使用常规语法:
let theSecretKey = Symbol("meaning of life");
myObject[theSecretKey] = 42;
Run Code Online (Sandbox Code Playgroud)
具有此键类型的属性将永远不会显示在for ... in循环等中,但仍可以是可枚举的且不可枚举的,因为函数Object.assign对于非可枚举属性的工作方式不同.
Object.getOwnPropertyNames不会得到symbol对象的键,但相似的命名Object.getOwnPropertySymbols将成功.
隐藏对象上的属性的最强方法是不将它存储在对象上.在ES6之前,这有点棘手,但现在我们有了弱映射.
弱映射基本上是Map一个键值存储,它不会保留(强)对键的引用,因此它们可以被垃圾收集.弱映射非常有限,并且不允许您枚举其键(这是设计).但是,如果您获得对某个地图键的引用,则可以获得与其相关的值.
它们主要用于允许扩展对象而无需实际修改它们.
基本思路是创建一个弱映射:
let weakMap = new WeakMap();
Run Code Online (Sandbox Code Playgroud)
并使用您想要扩展为对象的对象.然后,值将是属性集,可以是{}对象的形式,也可以是Map数据结构的形式.
weakMap.set(myObject, {
"meaning of life" : 42
});
Run Code Online (Sandbox Code Playgroud)
这种方法的优点是,有人需要获取对您的weakMap实例和密钥的引用,以便获取值,或者甚至知道它们存在.没有办法解决这个问题.所以它是100%,保证是安全的.以这种方式隐藏属性可确保用户不会发现它们,并且您的Web应用程序永远不会被黑客攻击*
当然,所有这一切中最大的缺陷是,这并不能创造出实际的财产.所以它不参与原型链等.
(*) 这是个谎言.
| 归档时间: |
|
| 查看次数: |
15144 次 |
| 最近记录: |