2012-07-31 63 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

相關問題