有没有办法将元数据添加到JavaScript对象?

时间:2022-10-22 16:58:01

I would like to add key-value pairs of metadata to arbitrary JavaScript objects. This metadata should not affect code that is not aware of the metadata, that means for example

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

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

MetaData aware code should be able to retrieve the data by key, i.e.

元数据识别代码应该能够通过密钥检索数据,即

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

Is there any way to do it - in node.js? If so, does it work with builtin types such as String and even Number ? (Edit Thinking about it, I don't care about real primitives like numbers, but having that for string instances would be nice).

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

Some Background: What I'm trying to do is cache values that are derived from an object with the object itself, so that

一些背景:我要做的是缓存从具有对象本身的对象派生的值,以便这样做

  • to meta data unaware code, the meta data enriched object will look the same as the original object w/o meta
  • 对于元数据不知情的代码,元数据丰富的对象看起来与原始对象w / o元相同

  • code that needs the derived values can get it out of the meta-data if already cached
  • 如果已缓存,则需要派生值的代码可以从元数据中获取它

  • the cache will get garbage collected alongside the object
  • 缓存将在对象旁边收集垃圾

Another way would be to store a hash table with the caches somewhere, but you'd never know when the object gets garbage collected. Every object instance would have to be taken care of manually, so that the caches don't leak.

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

(btw clojure has this feature: http://clojure.org/metadata)

(btw clojure有这个功能:http://clojure.org/metadata)

4 个解决方案

#1


7  

You can use ECMA5's new object properties API to store properties on objects that will not show up in enumeration but are nonetheless retrievable.

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

More information here: link

更多信息:链接

However you're not going to be able to do this on primitive types such as strings or numbers, only on complex types.

但是,您无法在原始类型(如字符串或数字)上执行此操作,只能在复杂类型上执行此操作。

[EDIT]

Another approach might be to utilise a data type's prototype to store meta. (Warning, hack ahead). So for strings:

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

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

However this is clearly not ideal. For one thing, if the string was collected or aliased (since simple data types are copied by value, not reference) you would lose this meta. Only the first approach has any mileage in a real-world environment, to be honest.

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

#2


4  

ES6 spec introduces Map and WeakMap. You can enable these in node by running node --harmony and by enabling the experimental javascript flag in Chrome, (it's also in Firefox by default). Maps and WeakMaps allow objects to be used as keys which can be be used to store metadata about objects that isn't visible to anyone without access to the specific map/weakmap. This is a pattern I now use a lot:

ES6规范引入了Map和WeakMap。您可以通过运行节点--harmony并在Chrome中启用实验性javascript标志来启用节点中的这些(默认情况下也在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;
  };
}

Use is simple and powerful:

使用简单而有力:

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

It also facilitates some interesting uses for separating implementation from interface:

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

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();
}

#3


1  

There is no "comment" system in JSON. The best you can hope for is to add a property with an unlikely name, and add that key contaning the metadata. You can then read the metadata back out if you know it's metadata, but other setups will just see it as another property. And if someone uses for..in...

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

#4


1  

You could just add the Metadata as a "private" variable!?

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

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

#1


7  

You can use ECMA5's new object properties API to store properties on objects that will not show up in enumeration but are nonetheless retrievable.

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

More information here: link

更多信息:链接

However you're not going to be able to do this on primitive types such as strings or numbers, only on complex types.

但是,您无法在原始类型(如字符串或数字)上执行此操作,只能在复杂类型上执行此操作。

[EDIT]

Another approach might be to utilise a data type's prototype to store meta. (Warning, hack ahead). So for strings:

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

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

However this is clearly not ideal. For one thing, if the string was collected or aliased (since simple data types are copied by value, not reference) you would lose this meta. Only the first approach has any mileage in a real-world environment, to be honest.

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

#2


4  

ES6 spec introduces Map and WeakMap. You can enable these in node by running node --harmony and by enabling the experimental javascript flag in Chrome, (it's also in Firefox by default). Maps and WeakMaps allow objects to be used as keys which can be be used to store metadata about objects that isn't visible to anyone without access to the specific map/weakmap. This is a pattern I now use a lot:

ES6规范引入了Map和WeakMap。您可以通过运行节点--harmony并在Chrome中启用实验性javascript标志来启用节点中的这些(默认情况下也在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;
  };
}

Use is simple and powerful:

使用简单而有力:

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

It also facilitates some interesting uses for separating implementation from interface:

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

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();
}

#3


1  

There is no "comment" system in JSON. The best you can hope for is to add a property with an unlikely name, and add that key contaning the metadata. You can then read the metadata back out if you know it's metadata, but other setups will just see it as another property. And if someone uses for..in...

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

#4


1  

You could just add the Metadata as a "private" variable!?

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

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