stable.js
function stringifyReplacerArr (key, value, stack, replacer) {
  var i, res
  // If the value has a toJSON method, call it to obtain a replacement value.
  if (typeof value === 'object' && value !== null && typeof value.toJSON === 'function') {
    value = value.toJSON(key)
  }

  switch (typeof value) {
    case 'object':
      if (value === null) {
        return 'null'
      }
      for (i = 0; i < stack.length; i++) {
        if (stack[i] === value) {
          return '"[Circular]"'
        }
      }
      if (Array.isArray(value)) {
        if (value.length === 0) {
          return '[]'
        }
        stack.push(value)
        res = '['
        // Use null as placeholder for non-JSON values.
        for (i = 0; i < value.length - 1; i++) {
          const tmp = stringifyReplacerArr(i, value[i], stack, replacer)
          res += tmp !== undefined ? tmp : 'null'
          res += ','
        }
        const tmp = stringifyReplacerArr(i, value[i], stack, replacer)
        res += tmp !== undefined ? tmp : 'null'
        res += ']'
        stack.pop()
        return res
      }

      if (replacer.length === 0) {
        return '{}'
      }
      stack.push(value)
      res = '{'
      var separator = ''
      for (i = 0; i < replacer.length; i++) {
        if (typeof replacer[i] === 'string' || typeof replacer[i] === 'number') {
          key = replacer[i]
          const tmp = stringifyReplacerArr(key, value[key], stack, replacer)
          if (tmp !== undefined) {
            res += `${separator}"${strEscape(key)}":${tmp}`
            separator = ','
          }
        }
      }
      res += '}'
      stack.pop()
      return res
    case 'string':
      return `"${strEscape(value)}"`
    case 'number':
      // JSON numbers must be finite. Encode non-finite numbers as null.
      return isFinite(value) ? String(value) : 'null'
    case 'boolean':
      return value === true ? 'true' : 'false'
  }
}
function stringifyReplacerArr (key, value, stack, replacer) {
  var i, res
  // If the value has a toJSON method, call it to obtain a replacement value.
  if (typeof value === 'object' && value !== null && typeof value.toJSON === 'function') {
    value = value.toJSON(key)
  }

  switch (typeof value) {
    case 'object':
      if (value === null) {
        return 'null'
      }
      for (i = 0; i < stack.length; i++) {
        if (stack[i] === value) {
          return '"[Circular]"'
        }
      }
      if (Array.isArray(value)) {
        if (value.length === 0) {
          return '[]'
        }
        stack.push(value)
        res = '['
        // Use null as placeholder for non-JSON values.
        for (i = 0; i < value.length - 1; i++) {
          const tmp = stringifyReplacerArr(i, value[i], stack, replacer)
          res += tmp !== undefined ? tmp : 'null'
          res += ','
        }
        const tmp = stringifyReplacerArr(i, value[i], stack, replacer)
        res += tmp !== undefined ? tmp : 'null'
        res += ']'
        stack.pop()
        return res
      }

      if (replacer.length === 0) {
        return '{}'
      }
      stack.push(value)
      res = '{'
      var separator = ''
      for (i = 0; i < replacer.length; i++) {
        if (typeof replacer[i] === 'string' || typeof replacer[i] === 'number') {
          key = replacer[i]
          const tmp = stringifyReplacerArr(key, value[key], stack, replacer)
          if (tmp !== undefined) {
            res += `${separator}"${strEscape(key)}":${tmp}`
            separator = ','
          }
        }
      }
      res += '}'
      stack.pop()
      return res
    case 'string':
      return `"${strEscape(value)}"`
    case 'number':
      // JSON numbers must be finite. Encode non-finite numbers as null.
      return isFinite(value) ? String(value) : 'null'
    case 'boolean':
      return value === true ? 'true' : 'false'
  }
}
function stringifyReplacerArr ( key , value , stack , replacer ) { var i , res // If the value has a toJSON method, call it to obtain a replacement value. if ( typeof value === 'object' && value !== null && typeof value . toJSON === 'function' ) { value = value . toJSON ( key ) } switch ( typeof value ) { case 'object' : if ( value === null ) { return 'null' } for ( i = 0 ; i < stack . length ; i ++ ) { if ( stack [ i ] === value ) { return '"[Circular]"' } } if ( Array . isArray ( value ) ) { if ( value . length === 0 ) { return '[]' } stack . push ( value ) res = '[' // Use null as placeholder for non-JSON values. for ( i = 0 ; i < value . length - 1 ; i ++ ) { const tmp = stringifyReplacerArr ( i , value [ i ] , stack , replacer ) res += tmp !== undefined ? tmp : 'null' res += ',' } const tmp = stringifyReplacerArr ( i , value [ i ] , stack , replacer ) res += tmp !== undefined ? tmp : 'null' res += ']' stack . pop ( ) return res } if ( replacer . length === 0 ) { return '{}' } stack . push ( value ) res = '{' var separator = '' for ( i = 0 ; i < replacer . length ; i ++ ) { if ( typeof replacer [ i ] === 'string' || typeof replacer [ i ] === 'number' ) { key = replacer [ i ] const tmp = stringifyReplacerArr ( key , value [ key ] , stack , replacer ) if ( tmp !== undefined ) { res += ` ${ separator } ${ strEscape ( key ) } ${ tmp } ` separator = ',' } } } res += '}' stack . pop ( ) return res case 'string' : return ` ${ strEscape ( value ) } ` case 'number' : // JSON numbers must be finite. Encode non-finite numbers as null. return isFinite ( value ) ? String ( value ) : 'null' case 'boolean' : return value === true ? 'true' : 'false' } }
Supports only the replacer option
Supports only the replacer option