2010-09-10 25 views
18

Tôi đang tìm một giải pháp để serialize (và unserialize) đối tượng Javascript vào một chuỗi trên các trình duyệt, bao gồm các thành viên của đối tượng xảy ra được chức năng. Một đối tượng điển hình sẽ trông giống như sau:Javascript: stringify đối tượng (bao gồm cả các thành viên của chức năng loại)

{ 
    color: 'red', 
    doSomething: function (arg) { 
     alert('Do someting called with ' + arg); 
    } 
} 

doSomething() sẽ chỉ chứa các biến cục bộ (không cần phải tuần tự hóa ngữ cảnh gọi!).

JSON.stringify() sẽ bỏ qua thành viên 'doSomething' vì đó là hàm. Tôi biết phương thức toSource() sẽ làm những gì tôi muốn nhưng đó là FF cụ thể.

+1

tôi sẽ chỉ để lại nhận xét vì tôi không cung cấp một giải pháp đầy đủ. Một thứ có thể giúp là bạn có thể xâu chuỗi một hàm bằng một lệnh gọi 'toString()'. http://jsfiddle.net/HFMaz/ Không chắc chắn về hỗ trợ đa trình duyệt. – user113716

+1

điều này được yêu cầu thường xuyên nhưng tôi không thể tìm thấy bất cứ điều gì có liên quan: \ lý do tại sao bạn có cần phải tuần tự hóa chức năng không? có lẽ có cách nào tốt hơn để sắp xếp mã của bạn? – lincolnk

+0

Điều này dành cho dự án WYSIWYG. Mỗi đối tượng Javascript (với các phương thức) định nghĩa hành vi của các thành phần trang. Nội dung trang (bao gồm cả hành vi JS) phải được lưu phía máy chủ, do đó được tuần tự hóa. –

Trả lời

5

Một cách nhanh chóng và dơ bẩn sẽ là như thế này:

Object.prototype.toJSON = function() { 
    var sobj = {}, i; 
    for (i in this) 
    if (this.hasOwnProperty(i)) 
     sobj[i] = typeof this[i] == 'function' ? 
     this[i].toString() : this[i]; 

return sobj; 

}; 

Rõ ràng điều này sẽ ảnh hưởng đến sự tuần tự của tất cả các đối tượng trong mã của bạn, và có thể vấp lên mã niave sử dụng lọc for in vòng. Cách "thích hợp" sẽ là viết một hàm đệ quy có thể thêm hàm toJSON vào tất cả các thành viên con cháu của bất kỳ đối tượng nào, xử lý các tham chiếu vòng tròn và như vậy. Tuy nhiên, giả sử Javascript đơn luồng (không có Web Worker), phương thức này sẽ hoạt động và không tạo ra bất kỳ tác dụng phụ không mong muốn nào.

Một hàm tương tự phải được thêm vào mẫu của Array để ghi đè đối tượng bằng cách trả về mảng chứ không phải đối tượng. Một tùy chọn khác sẽ được gắn một duy nhất và để cho nó có chọn lọc trả lại một mảng hoặc một đối tượng tùy thuộc vào bản chất của đối tượng nhưng nó có lẽ sẽ chậm hơn.

function JSONstringifyWithFuncs(obj) { 
    Object.prototype.toJSON = function() { 
    var sobj = {}, i; 
    for (i in this) 
     if (this.hasOwnProperty(i)) 
     sobj[i] = typeof this[i] == 'function' ? 
      this[i].toString() : this[i]; 

    return sobj; 
    }; 
    Array.prototype.toJSON = function() { 
     var sarr = [], i; 
     for (i = 0 ; i < this.length; i++) 
      sarr.push(typeof this[i] == 'function' ? this[i].toString() : this[i]); 

     return sarr; 
    }; 

    var str = JSON.stringify(obj); 

    delete Object.prototype.toJSON; 
    delete Array.prototype.toJSON; 

    return str; 
} 

http://jsbin.com/yerumateno/2/edit

+1

Tuyệt vời, ngoại trừ mảng không được tuần tự hóa thành mảng nữa. – Adaptabi

+3

Chức năng phân tích cú pháp trông như thế nào? Tất cả các hàm đều nằm trong các chuỗi để phân tích cú pháp, chúng ta cần phải chuyển đổi chúng trở lại các hàm. – Justin

0

Something như thế này ...

(function(o) { 
    var s = ""; 
    for (var x in o) { 
     s += x + ": " + o[x] + "\n"; 
    } 
    return s; 
})(obj) 

Lưu ý: đây là một biểu hiện. Nó trả về một biểu diễn chuỗi của đối tượng được truyền vào như một đối số (trong ví dụ của tôi, tôi chuyển qua một biến có tên là obj).

Bạn cũng có thể ghi đè lên phương thức toString của nguyên mẫu của Object:

Object.prototype.toString = function() { 
    // define what string you want to return when toString is called on objects 
} 
1

Đó là bất khả thi nếu không có sự giúp đỡ của các đối tượng chính nó. Ví dụ, làm thế nào bạn sẽ serialize kết quả của biểu thức này?

 
(function() { 
    var x; 
    return { 
     get: function() { return x; }, 
     set: function (y) { return x = y; } 
    }; 
})(); 

Nếu quý khách chỉ mất nội dung của chức năng, sau đó khi bạn deserialize, x sẽ tham khảo các biến toàn cầu, không phải là một trong một đóng cửa. Ngoài ra, nếu chức năng của bạn đóng trên trạng thái trình duyệt (như tham chiếu đến một div), bạn sẽ phải suy nghĩ về những gì bạn muốn có nghĩa là.

Tất nhiên, bạn có thể viết các phương thức của riêng bạn cho từng đối tượng mã hóa ngữ nghĩa bạn muốn tham chiếu đến các đối tượng khác.

5

Bạn có thể sử dụng JSON.stringify với một replacer như:

JSON.stringify({ 
    color: 'red', 
    doSomething: function (arg) { 
     alert('Do someting called with ' + arg); 
    } 
}, function(key, val) { 
     return (typeof val === 'function') ? '' + val : val; 
}); 
+2

Tôi đã kết thúc bằng cách sử dụng 'JSON.stringify (myObject, function (key, val) {return (typeof val === 'function')? '[Function]': val;}, 4);' và kết quả đầu ra thực sự tốt đẹp . –

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