Handling Functions and Undefined in JavaScript JSON

When converting JavaScript data into a JSON string using JSON.stringify(), functions and undefined values receive special treatment because they are not valid data types in the JSON standard. Depending on where these values exist—whether inside an object, an array, or passed as standalone values—JavaScript either omits them, replaces them with null, or returns undefined. This article explains the exact serialization rules for functions and undefined values in JavaScript and demonstrates how to customize this behavior.

Default Serialization Behavior

The JSON format only supports strings, numbers, booleans, objects, arrays, and null. When JSON.stringify() encounters functions or undefined, it applies the following rules:

1. Inside Objects (Omitted)

When a function or undefined value is a property value within an object, JSON.stringify() omits the key-value pair completely.

const user = {
  name: "Alice",
  age: undefined,
  greet: function() { return "Hello"; }
};

console.log(JSON.stringify(user));
// Output: {"name":"Alice"}

2. Inside Arrays (Converted to null)

When a function or undefined is an element inside an array, it is converted into null to preserve the index positions of the other elements.

const list = ["apple", undefined, function() { return 42; }, "banana"];

console.log(JSON.stringify(list));
// Output: ["apple",null,null,"banana"]

3. As Standalone Values (Returns undefined)

When passed directly as a single value (not inside an object or array), both functions and undefined return undefined rather than a string.

console.log(JSON.stringify(undefined)); 
// Output: undefined

console.log(JSON.stringify(() => {})); 
// Output: undefined

Why JSON Discards Functions and Undefined

JSON (JavaScript Object Notation) is a language-agnostic data interchange format. While inspired by JavaScript syntax, JSON does not allow executable code (functions) for security and cross-language compatibility reasons. Similarly, undefined is a JavaScript-specific primitive that does not exist in standard JSON; JSON uses null to represent the intentional absence of a value.


Customizing Serialization

If you need to preserve, modify, or log functions and undefined values during serialization, you can use the built-in customization options of JSON.stringify().

Using a Replacer Function

The replacer parameter allows you to inspect and transform values before they are serialized:

const data = {
  status: undefined,
  log: function() { console.log("running"); }
};

const jsonString = JSON.stringify(data, (key, value) => {
  if (typeof value === "function") {
    return value.toString(); // Serialize function as a string
  }
  if (value === undefined) {
    return null; // Convert undefined to null explicitly
  }
  return value;
});

console.log(jsonString);
// Output: {"status":null,"log":"function() { console.log(\"running\"); }"}

Using the toJSON() Method

If an object contains a toJSON() method, JSON.stringify() calls that method and serializes the returned value instead of the original object:

const profile = {
  username: "johndoe",
  getRole: () => "admin",
  toJSON() {
    return {
      username: this.username,
      role: this.getRole()
    };
  }
};

console.log(JSON.stringify(profile));
// Output: {"username":"johndoe","role":"admin"}