2012-07-31 33 views
5

Tôi muốn thêm cặp khóa-giá trị siêu dữ liệu vào các đối tượng JavaScript tùy ý. Siêu dữ liệu này không ảnh hưởng đến mã mà không nhận thức được các siêu dữ liệu, có nghĩa là ví dụCó cách nào để thêm siêu dữ liệu vào các đối tượng JavaScript không?

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

MetaData đang nhận thức được sẽ có thể lấy dữ liệu theo mã, tức là

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

Có cách nào để làm điều đó - trong node.js? Nếu vậy, nó có hoạt động với các loại nội trang dựng sẵn như String và thậm chí Number ? (Chỉnh sửa Suy nghĩ về điều đó, tôi không quan tâm về số thực nguyên thủy giống như số, nhưng việc đó cho các trường hợp chuỗi sẽ tốt hơn).

Một số Bối cảnh: Những gì tôi đang cố gắng làm là giá trị bộ nhớ cache mà có nguồn gốc từ một đối tượng với các đối tượng chính nó, do đó

  • dữ liệu meta đang không biết, các dữ liệu meta đối tượng phong phú sẽ trông giống như đối tượng gốc w/o meta đang
  • mà cần các giá trị có nguồn gốc có thể lấy nó ra khỏi meta-data nếu đã lưu trữ
  • bộ nhớ cache sẽ được thu gom rác thải cùng với các đối tượng

Một cách khác là lưu trữ một bảng băm với bộ đệm ở đâu đó, nhưng bạn sẽ không bao giờ biết khi nào đối tượng bị thu gom rác. Mỗi thể hiện đối tượng sẽ phải được xử lý thủ công, để các cache không bị rò rỉ.

(btw clojure có tính năng này: http://clojure.org/metadata)

+0

âm thanh này giống như chức năng 'jQuery.data()' với tôi –

Trả lời

7

Bạn có thể sử dụng API thuộc tính đối tượng mới của ECMA5 để lưu trữ các thuộc tính trên các đối tượng sẽ không hiển thị trong liệt kê nhưng vẫn có thể truy xuất được.

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" 

biết thêm thông tin ở đây: link

Tuy nhiên bạn sẽ không có khả năng làm điều này trên các kiểu dữ liệu như chuỗi hoặc số, chỉ trên các loại phức tạp.

[EDIT]

Một cách tiếp cận khác có thể là sử dụng nguyên mẫu loại dữ liệu để lưu trữ meta. (Cảnh báo, hack trước). Vì vậy, đối với chuỗi:

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

Tuy nhiên điều này rõ ràng không lý tưởng. Đối với một điều, nếu chuỗi được thu thập hoặc bí danh (vì các kiểu dữ liệu đơn giản được sao chép theo giá trị, không phải tham chiếu), bạn sẽ mất meta này. Chỉ có cách tiếp cận đầu tiên có số dặm trong một môi trường thực tế, thành thật mà nói.

+0

Điều đó kỳ quái và hấp dẫn. Liệu tính không thể liệt kê hành vi được chỉ định hay chỉ là hậu quả của việc hỗ trợ trình duyệt? – Beejamin

+1

Không có thiết kế, một phần của đặc tính đối tượng mới trong ECMA5. Có thể quy định rằng các thuộc tính * nên * được liệt kê, nhưng theo mặc định thì chúng không được. Tôi đã làm [một blog rộng rãi về điều này] (http://www.mitya.co.uk/blog/2012/Feb/ECMAScript-revolution-object-properties-201) một số thời gian trước đây có thể hữu ích. – Utkanos

+0

Tuyệt vời - cảm ơn vì đã làm rõ. Tôi đã học được một cái gì đó mới ngày hôm nay! – Beejamin

0

Không có hệ thống "bình luận" trong JSON. Điều tốt nhất bạn có thể hy vọng là thêm thuộc tính với tên không chắc chắn và thêm khóa đó chứa siêu dữ liệu. Sau đó, bạn có thể đọc siêu dữ liệu trở lại nếu bạn biết đó là siêu dữ liệu, nhưng các thiết lập khác sẽ chỉ xem nó là một thuộc tính khác. Và nếu ai đó sử dụng for..in ...

+0

-1 Xem câu trả lời của * Utkanos * –

1

Bạn chỉ có thể thêm Siêu dữ liệu dưới dạng biến "riêng tư" !?

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

Một cái gì đó giống như 'thêm một đóng cửa mà đóng trên một biến riêng cho một đối tượng'. Vấn đề với điều này là hàm 'getMetaData' được liệt kê và mặc dù' JSON.stringify' không tuần tự hóa nó, nó sẽ xuất hiện trong một 'for (var k in ins_ob)' chẳng hạn. –

4

ES6 spec giới thiệu Bản đồ và bản đồ yếu. Bạn có thể bật các nút này trong nút bằng cách chạy node --harmony và bằng cách bật cờ javascript thử nghiệm trong Chrome (mặc định nó cũng có trong Firefox). Bản đồ và WeakMaps cho phép các đối tượng được sử dụng làm khóa có thể được sử dụng để lưu trữ siêu dữ liệu về các đối tượng không hiển thị với bất kỳ ai không có quyền truy cập vào bản đồ/bản đồ yếu. Đây là một mô hình bây giờ tôi sử dụng rất nhiều:

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

Sử dụng rất đơn giản và mạnh mẽ:

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

Nó cũng tạo điều kiện cho một số sử dụng thú vị để tách thực hiện từ giao diện:

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

Thú vị. Cảm ơn đã chỉ cho tôi đến ES6, không biết về sự tồn tại của nó. Nhìn vào bản dự thảo hiện tại của spec, từ 'WeakMap' hoặc thậm chí chỉ là' weak' không có trong đó. Điều này cho chúng ta biết điều gì đó về tỷ lệ cược của WeakMaps được đưa vào ES6 hay tại sao nó không có trong đó. –

+0

Điều này cũng chỉ có thể được sử dụng với các đối tượng, không phải với các chuỗi. Vì vậy, sự khác biệt chính giữa đề xuất * Utkanos * và 'WeakMap' sẽ là WeakMaps cho phép bạn ngăn chặn người khác nhìn thấy và sửa đổi siêu dữ liệu. –

+0

Bản đồ WeakMap yêu cầu các phím là đối tượng nhưng Bản đồ thì không. Trong mã của tôi ở trên bạn chỉ cần thay đổi WeakMap để Bản đồ và nhận được kết quả mong muốn. Theo như bao gồm trong ES6, nó chắc chắn sẽ được nhưng đối với một số lý do chỉ là không có trong spec chưa. Nó đã được triển khai trong V8 và Spidermonkey, một trong những tính năng ES6 đầu tiên được triển khai. Bạn có thể tìm thấy nó trên http://wiki.ecmascript.org/doku.php?id=harmony:proposals liệt kê các đề xuất ES6 được chấp nhận. http://wiki.ecmascript.org/doku.php?id=harmony:simple_maps_and_sets http://wiki.ecmascript.org/doku.php?id = harmony: weak_maps –

Các vấn đề liên quan