Skip to content

Instantly share code, notes, and snippets.

@KosarevDmitry
Last active October 5, 2025 12:56
Show Gist options
  • Save KosarevDmitry/89ccf615cc795612f5c7716756f2082f to your computer and use it in GitHub Desktop.
Save KosarevDmitry/89ccf615cc795612f5c7716756f2082f to your computer and use it in GitHub Desktop.
Serialize prototype chain
/*
import {serializePrototypeChain} from "./serializePrototypeChain.js";
function Baz(){}
let obj = serializePrototypeChain(Baz);
let str = JSON.stringify(obj);
debugger
*/
// serializePrototypeChain.js
export function serializePrototypeChain(obj) {
const serializedChain = [];
let current = obj;
// Keep track of seen objects to handle circular references
const seenObjects = new WeakSet();
while (current) {
if (seenObjects.has(current)) {
// Handle circular reference: e.g., store a reference ID or skip
serializedChain.push({ __circularRef: true });
break;
}
// add to weaklist
seenObjects.add(current);
// object
const levelData = {
// ctor is not part of properties, so it need to fix separately
constructorName: current.constructor ? current.constructor.name : 'Object',
properties: {},
};
// Get all own property names (enumerable and non-enumerable)
const propertyNames = Object.getOwnPropertyNames(current);
for (const name of propertyNames) {
try {
// receive descriptors
const descriptor = Object.getOwnPropertyDescriptor(current, name);
if (descriptor) {
// Serialize value based on type (handle functions, objects, etc.)
if (typeof descriptor.value === 'function') {
// it returns out that if this is a property so we save it without calling recursion
levelData.properties[name] = `[Function: ${name}]`; // Represent functions
} else if (typeof descriptor.value === 'object' && descriptor.value !== null) {
// Recursively serialize nested objects or store a reference
levelData.properties[name] = serializePrototypeChain(descriptor.value);
} else {
// case if it is not an object or a function
levelData.properties[name] = descriptor.value;
}
}
} catch (e) {
// Handle cases where property access might throw errors (e.g., security restrictions)
levelData.properties[name] = `[Error: ${e.message}]`;
}
}
serializedChain.push(levelData); // outer as regard to recursion
current = Object.getPrototypeOf(current);
}
return serializedChain;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment