SoFunction
Updated on 2025-02-28

9 major features and conversion rules for learning

1. Introduction

()  Method to convert oneJavaScript Convert an object or value to a JSON string if one is specifiedreplacerFunctions can optionally replace values, or the specified replacer is an array, then optionally only the attributes specified by the array.

grammar:

(value[, replacer [, space]])

parameter:

value The value to be serialized into a JSON string.

replacer Optional

  • If this parameter is a function, during the serialization process, each attribute of the serialized value will be converted and processed by the function;
  • If the parameter is an array, only the attribute names contained in this array will be serialized to the final JSON string;
  • If the parameter is null or not provided, all properties of the object will be serialized.

space Optional

  • Specifies the blank string used for indentation to beautify output (pretty-print);
  • If the parameter is a number, it represents how many spaces there are; the upper limit is 10.
  • If this value is less than 1, it means there are no spaces;
  • If the parameter is a string (when the string length exceeds 10 letters, take its first 10 letters), the string will be used as a space;
  • If the parameter is not provided (or null), there will be no spaces.

Return value:

A JSON string representing the given value.

abnormal:

  • When a loop reference is raised, the exception TypeError("cyclic object value") (loop object value)
  • When trying to convert the value of type BigInt, TypeError("BigInt value can't be serialized in JSON") will be thrown (BigInt value cannot be serialized in JSON).

Basic use:

Notice:

  • You can convert objects or values ​​(usually used to convert objects more often)
  • You can specify replacer to selectively replace function
  • You can also specify replacer as an array to convert specified properties

Here is just the most basic explanation on MDN. Let’s first try these features

1. Convert objects

(({ name: 'Fat-headed fish', sex: 'boy' })) // '{"name":"Fat-headed fish","sex":"boy"}'

2. Convert normal value

(('Fat-headed fish')) // "Fat-headed fish"((1)) // "1"
((true)) // "true"
((null)) // "null"

3. Specify replacer function

(({ name: 'Fat-headed fish', sex: 'boy', age: 100 }, (key, value) => {
  return typeof value === 'number' ? undefined : value
}))
// '{"name":"Fat-headed fish","sex":"boy"}'

4. Specify an array

(({ name: 'Fat-headed fish', sex: 'boy', age: 100 }, [ 'name' ]))
// '{"name":"Fat-headed fish"}'

5. Specify space (beautify output)

(({ name: 'Fat-headed fish', sex: 'boy', age: 100 }))
// '{"name":"Fat-end fat-headed fish","sex":"boy","age":100}'(({ name: 'Fat-headed fish', sex: 'boy', age: 100 }, null , 2))
/*
 {
 "name": "Fat-headed fish",
 "sex": "boy",
 "age": 100
 }
 */

2. 9 major features to remember

I used this method before, but I didn’t know his conversion rules in detail, and there were as many as 9.

Feature 1

undefined、any function andsymbolvalue,出现在非数组对象的属性value中时在序列化过程中会被忽略
undefined、any function andsymbolvalue出现在数组中时会被转换成 null。
undefined、any function andsymbolvalue被单独转换时,Will return undefined

// 1. The existence of these three values ​​in the object will be ignored(({
  name: 'Fat-headed fish',
  sex: 'boy',
  // Functions will be ignored  showName () {
    ('Fat-headed fish')
  },
  // undefined will be ignored  age: undefined,
  // Symbol will be ignored  symbolName: Symbol('Fat-headed fish')
}))
// '{"name":"Fat-end fat-headed fish","sex":"boy"}'
// 2. There are three values ​​in the array that will be converted into null(([
  'Fat-headed fish',
  'boy',
  // The function will be converted to null  function showName () {
    ('Fat-headed fish')
  },
  //Undefined will be converted to null  undefined,
  //Symbol will be converted to null  Symbol('Fat-headed fish')
]))
// '["Fat-end fat-headed fish","boy",null,null,null]'
// 3. The individual conversion will return undefined((
  function showName () {
    ('Fat-headed fish')
  }
)) // undefined
((undefined)) // undefined
((Symbol('Fat-headed fish'))) // undefined

Feature 2

The wrapping objects of Boolean values, numbers, and strings will be automatically converted to the corresponding original value during serialization.

(([new Number(1), new String("Fat-headed fish"), new Boolean(false)]))
// '[1,"Fat-headed fish",false]'

Feature Three

All withsymbolThe attributes that are attribute keys will be completely ignored, even ifreplacer These are mandatory in the parameter.

(({
  [Symbol('Fat-headed fish')]: 'Fat-headed fish'}
)) 
// '{}'
(({
  [ Symbol('Fat-headed fish') ]: 'Fat-headed fish',
}, (key, value) => {
  if (typeof key === 'symbol') {
    return value
  }
}))
// undefined

Feature 4

NaNandInfinity The values ​​and null of the format will be regarded as null.

(({
  age: NaN,
  age2: Infinity,
  name: null
}))
// '{"age":null,"age2":null,"name":null}'

Feature Five

If there is a conversion valuetoJSON() method, which defines what value will be serialized.

const toJSONObj = {
  name: 'Fat-headed fish',
  toJSON () {
    return ''
  }
}

((toJSONObj))
// ""

Feature 6

Date date is calledtoJSON() Convert it tostringString (same()), therefore it will be processed as a string.

const d = new Date()

(()) // 2021-10-05T14:01:23.932Z
((d)) // "2021-10-05T14:01:23.932Z"

Features 7

Performing this method on objects containing loop references (objects refer to each other, forming an infinite loop) will throw an error.

let cyclicObj = {
  name: 'Fat-headed fish',
}

 = cyclicObj

((cyclicObj))
// Converting circular structure to JSON

Feature 8

Other types of objects, includingMap/Set/WeakMap/WeakSet, only enumerable attributes will be serialized

let enumerableObj = {}

(enumerableObj, {
  name: {
    value: 'Fat-headed fish',
    enumerable: true
  },
  sex: {
    value: 'boy',
    enumerable: false
  },
})

((enumerableObj))
// '{"name":"Fat-headed fish"}'

Feature Nine

When trying to convertBigIntA value of type will throw an error

const alsoHuge = BigInt(9007199254740991)

((alsoHuge))
// TypeError: Do not know how to serialize a BigInt

3. Handwritten one

Finally finished learning againMany features! Let's handwritten a simple version based on these features (without replacer function and space)

Source code implementation:

const jsonstringify = (data) => {
  // Confirm whether an object has a circular reference  const isCyclic = (obj) => {
  // Use Set data type to store detected objects  let stackSet = new Set()
  let detected = false

  const detect = (obj) => {
    // If it is not an object type, you can skip it directly    if (obj && typeof obj != 'object') {
      return
    }
    // When the object to be checked already exists in stackSet, it means that there is a circular reference    if ((obj)) {
      return detected = true
    }
    // Save the current obj as stackSet    (obj)

    for (let key in obj) {
      // Check the properties under obj one by one      if ((key)) {
        detect(obj[key])
      }
    }
    // After the level detection is completed, delete the current object to prevent misjudgment    /*
 For example: The attributes of an object point to the same reference. If they are not deleted, they will be considered a circular reference.
       let tempObj = {
 name: 'Fat-headed fish'
         }
       let obj4 = {
 obj1: tempObj,
 obj2: tempObj
         }
 */
    (obj)
  }

  detect(obj)

  return detected
}

  // Features 7:  // Perform this method on objects containing loop references (objects refer to each other, forming an infinite loop) and an error will be thrown.  if (isCyclic(data)) {
    throw new TypeError('Converting circular structure to JSON')
  }

  // Feature Nine:  // When trying to convert a value of type BigInt, an error will be thrown  if (typeof data === 'bigint') {
    throw new TypeError('Do not know how to serialize a BigInt')
  }

  const type = typeof data
  const commonKeys1 = ['undefined', 'function', 'symbol']
  const getType = (s) => {
    return (s).replace(/\[object (.*?)\]/, '$1').toLowerCase()
  }

  // Non-object  if (type !== 'object' || data === null) {
    let result = data
    // Feature 4:    //NaN and Infinity formats and null will be regarded as null.    if ([NaN, Infinity, null].includes(data)) {
      result = 'null'
      // Feature 1:      // Undefined, arbitrary functions and symbol values ​​are converted separately, undefined will be returned    } else if ((type)) {
      // Get undefined directly, not a string 'undefined'      return undefined
    } else if (type === 'string') {
      result = '"' + data + '"'
    }

    return String(result)
  } else if (type === 'object') {
    // Feature 5:    // If there is a toJSON() method, the method defines what value will be serialized    // Feature 6:    // Date date calls toJSON() to convert it into a string string (same()), so it will be treated as a string.    if (typeof  === 'function') {
      return jsonstringify(())
    } else if ((data)) {
      let result = ((it) => {
        // Feature 1:        // `undefined`, `arbitrary function` and `symbol value` will be converted to `null` when appearing in the `array`.        return (typeof it) ? 'null' : jsonstringify(it)
      })

      return `[${result}]`.replace(/'/g, '"')
    } else {
      // Feature 2:      // The wrapping objects of boolean values, numbers, and strings will be automatically converted to the corresponding original value during serialization.      if (['boolean', 'number'].includes(getType(data))) {
        return String(data)
      } else if (getType(data) === 'string') {
        return '"' + data + '"'
      } else {
        let result = []
        // Feature 8        // Other types of objects, including Map/Set/WeakMap/WeakSet, will only serialize enumerable properties        (data).forEach((key) => {
          // Feature Three:          // All attributes with symbol as the attribute key will be completely ignored, even if they are included in the replacer parameter.          if (typeof key !== 'symbol') {
            const value = data[key]
            // Feature 1            // `undefined`, `arbitrary function` and `symbol value` will be ignored during serialization when appearing in the property value of `non-array object`            if (!(typeof value)) {
              (`"${key}":${jsonstringify(value)}`)
            }
          }
        })

        return `{${result}}`.replace(/'/, '"')
      }
    }
  }
}

Test one:

// 1. Test the basic output(jsonstringify(undefined)) // undefined 
(jsonstringify(() => { })) // undefined
(jsonstringify(Symbol('Fat-headed fish'))) // undefined
(jsonstringify((NaN))) // null
(jsonstringify((Infinity))) // null
(jsonstringify((null))) // null
(jsonstringify({
  name: 'Fat-headed fish',
  toJSON() {
    return {
      name: 'Fat-headed fish 2',
      sex: 'boy'
    }
  }
}))
// {"name":"Fat-end 2","sex":"boy"}
// 2. Compare with native conversion(jsonstringify(null) === (null));
// true
(jsonstringify(undefined) === (undefined));
// true
(jsonstringify(false) === (false));
// true
(jsonstringify(NaN) === (NaN));
// true
(jsonstringify(Infinity) === (Infinity));
// true
let str = "Fat-headed fish";
(jsonstringify(str) === (str));
// true
let reg = new RegExp("\w");
(jsonstringify(reg) === (reg));
// true
let date = new Date();
(jsonstringify(date) === (date));
// true
let sym = Symbol('Fat-headed fish');
(jsonstringify(sym) === (sym));
// true
let array = [1, 2, 3];
(jsonstringify(array) === (array));
// true
let obj = {
  name: 'Fat-headed fish',
  age: 18,
  attr: ['coding', 123],
  date: new Date(),
  uni: Symbol(2),
  sayHi: function () {
    ("hello world")
  },
  info: {
    age: 16,
    intro: {
      money: undefined,
      job: null
    }
  },
  pakingObj: {
    boolean: new Boolean(false),
    string: new String('Fat-headed fish'),
    number: new Number(1),
  }
}
(jsonstringify(obj) === (obj)) 
// true
((jsonstringify(obj)))
// {"name":"Front-end fat head fish","age":18,"attr":["coding",123],"date":"2021-10-06T14:59:58.306Z","info":{"age":16,"intro":{"job":null}},"pakingObj":{"boolean":false,"string":"Front-end fat head fish","number":1}}((obj))
// {"name":"Front-end fat head fish","age":18,"attr":["coding",123],"date":"2021-10-06T14:59:58.306Z","info":{"age":16,"intro":{"job":null}},"pakingObj":{"boolean":false,"string":"Front-end fat head fish","number":1}}
// 3. Test traversal objectslet enumerableObj = {}

(enumerableObj, {
  name: {
    value: 'Fat-headed fish',
    enumerable: true
  },
  sex: {
    value: 'boy',
    enumerable: false
  },
})

(jsonstringify(enumerableObj))
// {"name":"Fat-headed fish"}
// 4. Test loop references and Bigint
let obj1 = { a: 'aa' }
let obj2 = { name: 'Fat-headed fish', a: obj1, b: obj1 }
 = obj2

(jsonstringify(obj2))
// TypeError: Converting circular structure to JSON
(jsonStringify(BigInt(1)))
// TypeError: Do not know how to serialize a BigInt

From the above test, we can see that jsonstringify is basically consistent with its performance.

This is the end of this article about the 9 major characteristics of learning and conversion rules. For more related content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!