8

我想将元数据的键值对添加到任意 JavaScript 对象。此元数据不应影响不知道元数据的代码,这意味着例如

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

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

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

有没有办法做到这一点 - 在 node.js 中?如果是这样,它是否适用于内置类型,例如String andNumber?(编辑考虑一下,我不关心像数字这样的真正的原语,但是对于字符串实例来说会很好)。

一些背景:我正在尝试做的是缓存从对象派生的值与对象本身,以便

  • 对于元数据不知道的代码,元数据丰富的对象将看起来与没有元数据的原始对象相同
  • 如果已经缓存,需要派生值的代码可以将其从元数据中取出
  • 缓存将与对象一起收集垃圾

另一种方法是在某处存储带有缓存的哈希表,但您永远不知道对象何时被垃圾收集。每个对象实例都必须手动处理,以免缓存泄漏。

(顺便说一句,clojure 有这个功能:http ://clojure.org/metadata )

4

4 回答 4

8

您可以使用 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"

更多信息在这里:链接

但是,您无法对字符串或数字等原始类型执行此操作,只能对复杂类型执行此操作。

[编辑]

另一种方法可能是利用数据类型的原型来存储元数据。(警告,前进)。所以对于字符串:

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'));

然而,这显然不是理想的。一方面,如果字符串被收集或别名(因为简单数据类型是按值复制的,而不是引用),您将丢失此元数据。老实说,只有第一种方法在现实环境中具有任何意义。

于 2012-07-31T13:18:19.930 回答
7

ES6 规范引入了 Map 和 WeakMap。您可以通过在 Chrome 中运行并启用实验性 javascript 标志来在节点中启用这些node --harmony(默认情况下它也在 Firefox 中)。Maps 和 WeakMaps 允许将对象用作键,这些键可用于存储有关对象的元数据,这些元数据对任何人都不可见,而无需访问特定的 map/weakmap。这是我现在经常使用的模式:

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();
}
于 2012-08-04T09:06:43.897 回答
1

JSON 中没有“评论”系统。最好的办法是添加一个名称不太可能的属性,并添加包含元数据的键。然后,如果您知道元数据是元数据,则可以将元数据读回,但其他设置只会将其视为另一个属性。如果有人使用for..in...

于 2012-07-31T13:16:14.980 回答
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');
};
于 2012-07-31T13:30:29.773 回答