Làm cách nào để tuần tự hóa và giải tuần tự hóa một đối tượng trong JavaScript?

Có một lỗ hổng nhỏ (cố ý) trong hai hàm tiêu chuẩn được sử dụng rộng rãi của JavaScript, cụ thể là trong JSON.stringify và JSON.parse và lỗ hổng này liên quan đến đối tượng Ngày của JavaScript. Và cái lỗ này đôi khi có thể khiến bạn đau đầu

Chúng ta sẽ xem lỗ hổng này thực sự là gì và bạn sẽ học cách đối phó với nó một cách hiệu quả


Mục lục


Vấn đề

Bạn đã bao giờ thử JSON.stringify một đối tượng chứa Ngày chưa?

const obj = {
  date: new Date(),
  id: "foo"
};
const serialized = JSON.stringify(obj);
console.log(serialized); 
// => prints {"date":"2020-12-03T09:19:29.408Z","id":"foo"}

Nhưng bạn cũng đã thử JSON.parse cùng một đối tượng rồi kiểm tra loại thuộc tính chứa ngày ban đầu chưa?

const deserialized = JSON.parse(serialized);
console.log(typeof deserialized.date);
// => prints string

Vâng, bây giờ nó là một chuỗi


Lý do cho hành vi này

Bây giờ bạn có thể hỏi điều gì đó như “Tại sao JSON. parse không thể khôi phục ngày đúng không?” . Hàm có thể xác định rằng có một Ngày không?

Chà, khi JSON.stringify xếp thứ tự đối tượng của bạn, nó sẽ chuyển ngày thành một chuỗi. Đây là cách bạn thường tuần tự hóa các đối tượng ngày tháng bằng bất kỳ ngôn ngữ nào. Có các định dạng nổi tiếng cho các đối tượng ngày tháng, định dạng ngày tháng sẽ trông như thế nào khi nó được chuyển thành một chuỗi

Nhưng tại thời điểm này, khi ngày của bạn được sắp xếp theo thứ tự, nó sẽ mất thông tin. Ngày cũ giờ chỉ còn là một chuỗi đơn thuần, không hơn, không kém, và không có thêm thông tin nào về việc nó đã từng là một ngày tháng hay chưa. Và với việc mất thông tin này, một vấn đề khác phát sinh

Chuỗi này đã bao giờ là một ngày hay nó luôn là một chuỗi?

Không phải tất cả các đối tượng JSON mà bạn làm việc chỉ tồn tại trong mã và chương trình của riêng bạn. Một số trong số chúng di chuyển qua dây khi bạn tìm nạp dữ liệu từ API hoặc gửi dữ liệu đến giao diện người dùng. Đối tượng rời khỏi bộ nhớ chương trình của bạn và được tải lại vào bộ nhớ của chương trình khác và mã của chương trình đó có thể đã được thực hiện bởi một người khác, ở bất kỳ nơi nào khác trên thế giới

Những người tạo ra JSON.parse cũng gặp vấn đề tương tự. Họ cần suy nghĩ về cách triển khai phương pháp này theo cách nó hoạt động hiệu quả, vượt trội, cho càng nhiều người dùng càng tốt. Và đây là lý do tại sao họ quyết định không làm gì cả. Vâng, không có gì. Họ đã quyết định không thực hiện một số hành vi đặc biệt để xử lý các chuỗi trông giống như ngày tháng vì không có đủ thông tin để xử lý vấn đề đúng cách

Xem nó theo cách này. Các nhà phát triển cố tình chỉ tạo một chuỗi ngày được định dạng sẽ ngạc nhiên hoặc thậm chí tức giận nếu người dùng của họ luôn nhận được một đối tượng ngày tháng khi họ giải tuần tự hóa các đối tượng của mình và ngược lại, vì vậy người ta phải chọn một cách, làm một bên hài lòng và một bên hài lòng.

Hóa ra cách dễ nhất để giải quyết vấn đề này là chỉ cần để một chuỗi JSON là một chuỗi. Không cần bất kỳ trường hợp đặc biệt nào trong xử lý chuỗi. Nếu trình phân tích cú pháp thấy một thuộc tính có giá trị được đặt trong dấu ngoặc kép, nó chỉ cần đặt nó vào một chuỗi là xong


Tự mình giải quyết vấn đề

Được rồi, JSON.parse không thể giải quyết vấn đề về ngày tháng, nhưng bạn vẫn còn băn khoăn về cách tự mình giải quyết vấn đề

Ví dụ, bạn có thể đưa ra một giải pháp rất ngây thơ

const deserialized = JSON.parse(serialized);
const fixedDeserialized = {
  ...deserialized,
  date: new Date(deserialized.date)
};
console.log(typeof fixedDeserialized.date);
// => prints object

Nhưng giải pháp này có vẻ không phải là một giải pháp tốt vì nó đòi hỏi nhiều thao tác thủ công và viết mã. Và bây giờ hãy tưởng tượng làm đi làm lại điều này, cho mỗi và mọi đối tượng có cấu trúc khác với tất cả các đối tượng khác trước đó. Nghe có vẻ không phải là một điều tuyệt vời để làm, phải không?

Hóa ra những người tạo ra JSON.parse biết rằng sẽ có một số trường hợp các nhà phát triển khác muốn tùy chỉnh hành vi của trình phân tích cú pháp. Đây là lý do tại sao nguyên mẫu thực tế của JSON.parse trông như thế này.

const deserialized = JSON.parse(serialized);
console.log(typeof deserialized.date);
// => prints string
5

const deserialized = JSON.parse(serialized);
console.log(typeof deserialized.date);
// => prints string
6 là chuỗi mà bạn muốn phân tích cú pháp, nhưng đối số tùy chọn đó là gì 
const deserialized = JSON.parse(serialized);
console.log(typeof deserialized.date);
// => prints string
7?

Nếu là một hàm, điều này quy định cách giá trị ban đầu được tạo bằng cách phân tích cú pháp được chuyển đổi, trước khi được trả về

Đó là một chức năng tùy chỉnh, cho phép bạn viết logic tùy chỉnh và nó có nguyên mẫu sau.

const deserialized = JSON.parse(serialized);
console.log(typeof deserialized.date);
// => prints string
8

Như bạn có thể đã đoán, 

const deserialized = JSON.parse(serialized);
console.log(typeof deserialized.date);
// => prints string
9 là thuộc tính trong đối tượng JSON và 
const deserialized = JSON.parse(serialized);
const fixedDeserialized = {
  ...deserialized,
  date: new Date(deserialized.date)
};
console.log(typeof fixedDeserialized.date);
// => prints object
0 là giá trị thực của nó và hóa ra hàm này được gọi ngay sau khi trình phân tích cú pháp đã xử lý thuộc tính và giá trị của nó. Điều này có nghĩa là bạn sẽ không phải xử lý các công cụ cấp thấp như chuyển các chữ số chuỗi thành số, v.v. Tất cả điều đó đã được trình phân tích cú pháp thực hiện khi chức năng của bạn được gọi

Một cách dễ dàng để biết công cụ hồi sinh thực sự làm gì là dùng thử chức năng mũi tên rất đơn giản

JSON.parse(serialized, (key, value) => {
  console.log(key, value);
  return value;
});
// => prints
// date 2020-12-03T10:29:47.259Z 
// id foo 
// "" {date: "2020-12-03T10:32:05.595Z", id: "foo"}

Có vẻ như tất cả các thuộc tính và giá trị được truyền cho hàm và cuối cùng là toàn bộ đối tượng một lần nữa. Đây là một số thông tin mà bây giờ bạn có thể làm việc với để triển khai một chức năng biến chuỗi ngày của bạn thành đối tượng ngày thực một lần nữa

Là một cách triển khai đơn giản, bạn có thể sử dụng biểu thức chính quy để xác định xem một chuỗi có chứa chuỗi ngày ISO hay không và tạo một triển khai tự động xử lý việc giải tuần tự hóa thực tế

const isoDateRegex = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*))(?:Z|(\+|-)([\d|:]*))?$/;
function isIsoDate(value) {
  return isoDateRegex.exec(value);
}
function parseDate(ignored, value) {
  if (typeof value !== "string") {
    return value;
  }
  if (isIsoDate(value)) {
    return new Date(value);
  }
  return value;
}

Ngay sau khi bạn có triển khai này, bạn có thể sử dụng nó như chức năng mũi tên nội tuyến của mình trước đây

const deserialized = JSON.parse(serialized, parseDate);
console.log(typeof deserialized.date);
// => prints object

Và bạn có nó rồi đấy. Việc chuyển một trình khôi phục cho JSON.parse mỗi khi bạn thực sự cần sẽ tiết kiệm được nhiều mã hơn là viết một triển khai tùy chỉnh với nhiều dòng mã hơn mỗi lần

Làm cách nào để tuần tự hóa một đối tượng trong JavaScript?

Ví dụ: trong JavaScript, bạn có thể tuần tự hóa một đối tượng thành chuỗi JSON bằng cách gọi hàm JSON. stringify() . Các giá trị CSS được tuần tự hóa bằng cách gọi hàm CSSStyleDeclaration.

Làm cách nào để giải tuần tự hóa đối tượng đối tượng trong JavaScript?

Quá trình theo đó định dạng cấp thấp hơn (e. g. đã được chuyển qua mạng hoặc được lưu trữ trong kho lưu trữ dữ liệu) được dịch thành một đối tượng có thể đọc được hoặc cấu trúc dữ liệu khác. Ví dụ, trong JavaScript, bạn có thể giải tuần tự hóa một chuỗi JSON thành một đối tượng bằng cách gọi hàm JSON. phân tích cú pháp() .

Tuần tự hóa và giải tuần tự hóa trong JavaScript là gì?

Tuần tự hóa lấy cấu trúc dữ liệu trong bộ nhớ và chuyển đổi nó thành một chuỗi byte có thể được lưu trữ và chuyển giao. Deserialization lấy một loạt byte và chuyển đổi nó thành cấu trúc dữ liệu trong bộ nhớ có thể được sử dụng theo chương trình

Làm cách nào để tuần tự hóa đối tượng JSON trong JavaScript?

Cách thực hiện Tuần tự hóa JSON trong Javascript .
JSON. xâu chuỗi ().
Ví dụ. Khi đối số thứ hai là một hàm. .
Thụt lề chuỗi. Đối số thứ ba của JSON. .
Thụt lề với giá trị chuỗi. .
phương thức toJSON()