Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> JavaScript

Giữ function khi JSON.stringify() trong JavaScript

JSON.stringify() bỏ qua function (và undefined, Symbol) khi serialize object. Để giữ function, phải chuyển thành string trước.

Vấn đề: Function bị mất

<script>
  const person = {
    name: function() { return 'Ram + Rahim'; },
    designation: 'Developer',
    city: 'Hyderabad'
  };
  
  const json = JSON.stringify(person);
  document.write(json); 
  // {"designation":"Developer","city":"Hyderabad"} — name function MẤT
</script>

Giải pháp: Chuyển function → string trước khi stringify

<script>
  const obj = {
    name: function() { return 'Ram + Rahim'; },
    designation: 'Developer',
    city: 'Hyderabad'
  };
  
  // Chuyển function thành string representation
  obj.name = obj.name.toString();
  
  const json = JSON.stringify(obj);
  document.write(json);
  // {"name":"function () { return 'Ram + Rahim'; }","designation":"Developer","city":"Hyderabad"}
</script>

Cách khôi phục (Reviver) — Không khuyến khích cho production

const json = '{"name":"function () { return 1+2; }","value":10}';
const obj = JSON.parse(json, (key, value) => {
  if (typeof value === 'string' && value.startsWith('function')) {
    return eval('(' + value + ')'); // ⚠️ RỦI RO XSS — chỉ dùng trusted source
  }
  return value;
});

console.log(obj.name()); // 3

Cách tốt hơn: Không serialize function

Thiết kế data transfer không chứa function. Function là behavior, không phải data.

Pattern: Serialize data, attach behavior sau

// Server gửi data thuần
const userData = { name: 'Alice', role: 'admin', permissions: ['read','write'] };

// Client attach behavior
function createUser(data) {
  return {
    ...data,
    can(permission) {
      return this.permissions.includes(permission);
    },
    getDisplayName() {
      return `${this.name} (${this.role})`;
    }
  };
}

const user = createUser(userData);
user.can('read'); // true

Lưu ý

  • toString() trên function trả về source code (nếu không phải native) — có thể chứa comment, formatting khác nhau cross-engine.
  • eval() để revive function — rủi ro bảo mật nghiêm trọng.
  • Circular reference: JSON.stringify throw error — dùng flatted library hoặc custom replacer.