2012-07-31 81 views
5

我想向任意JavaScript对象添加元数据的键值对。该元数据应该不会影响代码,不知道元数据的,这意味着,例如有什么方法可以将元数据添加到JavaScript对象吗?

JSON.stringify(obj) === JSON.stringify(obj.WithMetaData('key', 'value')) 

元数据感知代码应该能够通过键检索数据,即

obj.WithMetaData('key', 'value').GetMetaData('key') === 'value' 

有什么办法做到这一点 - 在node.js?如果是这样,它是否适用于内置类型,如String 甚至 Number ? (编辑想一想吧,我不在乎真的原始像数字,但有字符串实例会很好)。

一些背景:我试图做的是,从与对象本身的对象派生的缓存值,这样

  • 到元数据不知道代码,元数据丰富对象将看原来一样的物体W/O需要导出的值可以把它弄出来的元数据,如果已经缓存
  • 缓存会得到垃圾回收旁边的对象元
  • 代码

另一种方法是将哈希表与某处的缓存进行存储,但是永远不会知道何时该对象被垃圾收集。每个对象实例都必须手工处理,以便缓存不会泄漏。

(顺便说一句的Clojure具有这样的特征:http://clojure.org/metadata

+0

这听起来就像'jQuery.data()'功能对我来说 – 2012-07-31 13:16:24

回答

7

您可以使用ECMA5的新对象属性API来存储不会在枚举中显示但仍可检索的对象的属性。

var myObj = {}; 
myObj.real_property = 'hello'; 
Object.defineProperty(myObj, 'meta_property', {value: 'some meta value'}); 
for (var i in myObj) 
    alert(i+' = '+myObj[i]); //only one property - @real_property 
alert(myObj.meta_property); //"some meta value" 

点击此处了解详情:link

但是你不会是能够做到这一点的基本类型,如字符串或数字,只在复杂类型。

[编辑]

的另一种方法可能是利用一个数据类型的原型来存储元。 (警告,前面的黑客)。因此,对于字符串:

String.prototype.meta = {}; 
String.prototype.addMeta = function(name, val) { this.meta[name] = val; } 
String.prototype.getMeta = function(name) { return this.meta[name]; }; 
var str = 'some string value'; 
str.addMeta('meta', 'val'); 
alert(str.getMeta('meta')); 

但是,这显然不理想。首先,如果字符串被收集或别名(因为简单的数据类型是通过值复制的,而不是引用),你会失去这个元。说实话,只有第一种方法在真实环境中有任何里程。

+0

这是奇怪的,有趣的。非可枚举是指定的行为,还是仅仅是浏览器支持的结果? – Beejamin 2012-07-31 13:21:15

+1

不是它的设计,而是ECMA5中新的对象属性规范的一部分。可以规定属性*应该是可枚举的,但默认情况下它们不是。我前段时间做了一个[广泛的博客](http://www.mitya.co.uk/blog/2012/Feb/ECMAScript-revolution-object-properties-201),可能有所帮助。 – Utkanos 2012-07-31 13:25:22

+0

太好了 - 谢谢你的澄清。我今天学了些新东西! – Beejamin 2012-07-31 13:27:05

0

有一个在JSON没有 “意见” 系统。您所希望的最好的方式是添加一个名称不太可能的属性,然后添加包含元数据的密钥。然后,如果知道元数据,则可以将元数据读出来,但其他设置只会将其视为另一个属性。如果有人使用for..in ...

+0

-1查看答案* Utkanos * – 2012-08-06 07:29:11

1

您可以将元数据添加为“私人”变量!?

var Obj = function (meta) { 
    var meta = meta; 
    this.getMetaData = function (key) { 
     //do something with the meta object 
     return meta; 
    }; 
}; 
var ins_ob = new Obj({meta:'meta'}); 
var ins_ob2 = new Obj(); 
if(JSON.stringify(ins_ob) === JSON.stringify(ins_ob2)) { 
    console.log('hoorai'); 
}; 
+0

就像'添加一个闭包,通过一个私有变量关闭对象'。这个问题是函数'getMetaData'是可枚举的,虽然'JSON.stringify'没有序列化它,它会在'for(var in in_ob)'中出现。 – 2012-08-06 07:37:06

4

ES6规范介绍了Map和WeakMap。您可以通过运行node --harmony并在Chrome中启用实验性JavaScript标志(在默认情况下也在Firefox中)在节点中启用这些标志。 Maps和WeakMaps允许将对象用作关键字,这些关键字可以用来存储关于对象的元数据,这些元数据对于没有访问特定映射/弱映射的任何人都是不可见的。这是一种模式我现在用了很多:

function createStorage(creator){ 
    creator = creator || Object.create.bind(null, null, {}); 
    var map = new Map; 
    return function storage(o, v){ 
    if (1 in arguments) { 
     map.set(o, v); 
    } else { 
     v = map.get(o); 
     if (v == null) { 
     v = creator(o); 
     map.set(o, v); 
     } 
    } 
    return v; 
    }; 
} 

使用简单,功能强大:

var _ = createStorage(); 

_(someObject).meta= 'secret'; 
_(5).meta = [5]; 
var five = new Number(5); 
_(five).meta = 'five'; 

console.log(_(someObject).name); 
console.log(_(5).meta); 
console.log(_(five).meta); 

它还有助于从接口的分离实现一些有趣的用途:

var _ = createStorage(function(o){ return new Backing(o) }); 

function Backing(o){ 
    this.facade = o; 
} 
Backing.prototype.doesStuff = function(){ 
    return 'real value'; 
} 

function Facade(){ 
    _(this); 
} 
Facade.prototype.doSomething = function doSomething(){ 
    return _(this).doesStuff(); 
} 
+0

有趣的东西。感谢您指点我ES6,不知道它的存在。从目前的规格草案来看,“WeakMap”这个词甚至是“weak”都不在其中。这是否告诉我们有关WeakMaps包含在ES6中的几率或为什么它不在那里。 – 2012-08-06 00:00:01

+0

这也只能用于对象,而不能与字符串一起使用。因此,* Utkanos *'建议与'WeakMap'之间的主要区别在于WeakMaps允许您阻止他人查看和修改元数据。 – 2012-08-06 00:23:45

+0

WeakMap要求键是对象,但Map不。在我上面的代码中,只需将WeakMap更改为Map并获得所需的结果即可。至于包含在ES6中,它肯定会是,但由于某种原因,只是不在规范中。它已经在V8和Spidermonkey中实现,这是首批实现的ES6功能之一。您可以在http://wiki.ecmascript.org/doku.php?id=harmony:建议列出已接受的ES6提案中找到它。 http://wiki.ecmascript.org/doku.php?id=harmony:simple_maps_and_sets http://wiki.ecmascript.org/doku.php?id = harmony:weak_maps – 2012-08-07 16:59:24

相关问题