Eug*_*sky 7 javascript v8 node.js
我想将元数据的键值对添加到任意JavaScript对象.此元数据不应影响不了解元数据的代码,例如,这意味着
JSON.stringify(obj) === JSON.stringify(obj.WithMetaData('key', 'value'))
Run Code Online (Sandbox Code Playgroud)
元数据感知代码应该能够通过密钥检索数据,即
obj.WithMetaData('key', 'value').GetMetaData('key') === 'value'
Run Code Online (Sandbox Code Playgroud)
有没有办法做到这一点 - 在node.js?如果是这样,它是否适用于内置类型String ,甚至是?(编辑思考它,我不关心像数字这样的真实原语,但是对于字符串实例来说这很好).Number
一些背景:我要做的是缓存从具有对象本身的对象派生的值,以便这样做
另一种方法是在某处存储带有缓存的哈希表,但是你永远不知道对象何时被垃圾收集.必须手动处理每个对象实例,以便缓存不会泄漏.
(btw clojure有这个功能:http://clojure.org/metadata)
您可以使用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"
Run Code Online (Sandbox Code Playgroud)
更多信息:链接
但是,您无法在原始类型(如字符串或数字)上执行此操作,只能在复杂类型上执行此操作.
[编辑]
另一种方法可能是利用数据类型的原型来存储元数据.(警告,黑客前进).所以对于字符串:
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'));
Run Code Online (Sandbox Code Playgroud)
然而,这显然不是理想的.首先,如果字符串被收集或别名(因为简单数据类型是按值复制而不是引用),您将丢失此元数据.说实话,只有第一种方法在现实环境中有任何里程.
小智 5
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;
};
}
Run Code Online (Sandbox Code Playgroud)
使用简单而强大:
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);
Run Code Online (Sandbox Code Playgroud)
它还有利于将实现与接口分离的一些有趣用途:
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();
}
Run Code Online (Sandbox Code Playgroud)