index.js
function stringify(obj, replacer, space) {

  if (typeof replacer === 'string' || typeof replacer === 'number') {
    // noinspection JSValidateTypes
    space = replacer;
    // noinspection JSValidateTypes
    replacer = undefined;
  }
  const replacerArgs = replacer ? replacer.length : 0;
  if (space && typeof space === 'number') {
    var i = space;
    space = ' ';
    while (i-- > 1)
      space += ' ';
  }

  const toString = function(o, k, v) {
    var z;
    if (replacerArgs === 2) {
      z = replacer(k, v);
      return z === undefined ? z : JSON.stringify(z);
    }
    if (replacerArgs === 3) {
      z = replacer(o, k, v);
      return z === undefined ? z : JSON.stringify(z);
    }
    return JSON.stringify(v);
  };

  var result = '';
  var indent = 0;
  const refs = [];
  const doStringify = function(obj, key, value) {
    // Check circular references
    const arrayOfObject = Array.isArray(value) || isPlainObject(value);
    if (arrayOfObject && refs.indexOf(value) >= 0) {
      result += '"[Circular]"';
      return;
    }
    const getIndent = function(n) {
      if (!space) return '';
      indent += (n || 0);
      var s = '\n';
      var k = indent;
      while (k-- > 0)
        s += space;
      return s;
    };

    var i;
    // serialize array
    if (Array.isArray(value)) {
      refs.push(value);
      result += '[' + getIndent(1);
      i = 0;
      value.forEach(function(v, k) {
        if (Array.isArray(v) || isPlainObject(v)) {
          result += (i ? ',' + getIndent() : '');
          doStringify(value, k, v);
          i++;
        } else {
          const s = toString(value, k, v);
          if (s !== undefined) {
            result += (i ? ',' + getIndent() : '') + s;
            i++;
          }
        }
      });
      result += getIndent(-1) + ']';
      refs[refs.indexOf(value)] = undefined;
      return;
    }
    // serialize object
    if (isPlainObject(value)) {
      refs.push(value);
      result += '{' + getIndent(1);
      i = 0;
      Object.getOwnPropertyNames(value).forEach(function(k) {
        const v = value[k];
        if (Array.isArray(v) || isPlainObject(v)) {
          result += (i ? ',' + getIndent() : '') +
              JSON.stringify(k) + ':' + (space ? ' ' : '');
          doStringify(value, k, v);
          i++;
        } else {
          const s = toString(value, k, v);
          if (s !== undefined) {
            result += (i ? ',' + getIndent() : '') +
                JSON.stringify(k) + ':' + (space ? ' ' : '') + s;
            i++;
          }
        }
      });
      result += getIndent(-1) + '}';
      refs[refs.indexOf(value)] = undefined;
      return;
    }
    // serialize values
    result += toString(obj, key, value);
  };
  doStringify(undefined, undefined, obj);
  return result;
}
function stringify(obj, replacer, space) {

  if (typeof replacer === 'string' || typeof replacer === 'number') {
    // noinspection JSValidateTypes
    space = replacer;
    // noinspection JSValidateTypes
    replacer = undefined;
  }
  const replacerArgs = replacer ? replacer.length : 0;
  if (space && typeof space === 'number') {
    var i = space;
    space = ' ';
    while (i-- > 1)
      space += ' ';
  }

  const toString = function(o, k, v) {
    var z;
    if (replacerArgs === 2) {
      z = replacer(k, v);
      return z === undefined ? z : JSON.stringify(z);
    }
    if (replacerArgs === 3) {
      z = replacer(o, k, v);
      return z === undefined ? z : JSON.stringify(z);
    }
    return JSON.stringify(v);
  };

  var result = '';
  var indent = 0;
  const refs = [];
  const doStringify = function(obj, key, value) {
    // Check circular references
    const arrayOfObject = Array.isArray(value) || isPlainObject(value);
    if (arrayOfObject && refs.indexOf(value) >= 0) {
      result += '"[Circular]"';
      return;
    }
    const getIndent = function(n) {
      if (!space) return '';
      indent += (n || 0);
      var s = '\n';
      var k = indent;
      while (k-- > 0)
        s += space;
      return s;
    };

    var i;
    // serialize array
    if (Array.isArray(value)) {
      refs.push(value);
      result += '[' + getIndent(1);
      i = 0;
      value.forEach(function(v, k) {
        if (Array.isArray(v) || isPlainObject(v)) {
          result += (i ? ',' + getIndent() : '');
          doStringify(value, k, v);
          i++;
        } else {
          const s = toString(value, k, v);
          if (s !== undefined) {
            result += (i ? ',' + getIndent() : '') + s;
            i++;
          }
        }
      });
      result += getIndent(-1) + ']';
      refs[refs.indexOf(value)] = undefined;
      return;
    }
    // serialize object
    if (isPlainObject(value)) {
      refs.push(value);
      result += '{' + getIndent(1);
      i = 0;
      Object.getOwnPropertyNames(value).forEach(function(k) {
        const v = value[k];
        if (Array.isArray(v) || isPlainObject(v)) {
          result += (i ? ',' + getIndent() : '') +
              JSON.stringify(k) + ':' + (space ? ' ' : '');
          doStringify(value, k, v);
          i++;
        } else {
          const s = toString(value, k, v);
          if (s !== undefined) {
            result += (i ? ',' + getIndent() : '') +
                JSON.stringify(k) + ':' + (space ? ' ' : '') + s;
            i++;
          }
        }
      });
      result += getIndent(-1) + '}';
      refs[refs.indexOf(value)] = undefined;
      return;
    }
    // serialize values
    result += toString(obj, key, value);
  };
  doStringify(undefined, undefined, obj);
  return result;
}
function stringify ( obj , replacer , space ) { if ( typeof replacer === 'string' || typeof replacer === 'number' ) { // noinspection JSValidateTypes space = replacer ; // noinspection JSValidateTypes replacer = undefined ; } const replacerArgs = replacer ? replacer . length : 0 ; if ( space && typeof space === 'number' ) { var i = space ; space = ' ' ; while ( i -- > 1 ) space += ' ' ; } const toString = function ( o , k , v ) { var z ; if ( replacerArgs === 2 ) { z = replacer ( k , v ) ; return z === undefined ? z : JSON . stringify ( z ) ; } if ( replacerArgs === 3 ) { z = replacer ( o , k , v ) ; return z === undefined ? z : JSON . stringify ( z ) ; } return JSON . stringify ( v ) ; } ; var result = '' ; var indent = 0 ; const refs = [ ] ; const doStringify = function ( obj , key , value ) { // Check circular references const arrayOfObject = Array . isArray ( value ) || isPlainObject ( value ) ; if ( arrayOfObject && refs . indexOf ( value ) >= 0 ) { result += '"[Circular]"' ; return ; } const getIndent = function ( n ) { if ( ! space ) return '' ; indent += ( n || 0 ) ; var s = '\n' ; var k = indent ; while ( k -- > 0 ) s += space ; return s ; } ; var i ; // serialize array if ( Array . isArray ( value ) ) { refs . push ( value ) ; result += '[' + getIndent ( 1 ) ; i = 0 ; value . forEach ( function ( v , k ) { if ( Array . isArray ( v ) || isPlainObject ( v ) ) { result += ( i ? ',' + getIndent ( ) : '' ) ; doStringify ( value , k , v ) ; i ++ ; } else { const s = toString ( value , k , v ) ; if ( s !== undefined ) { result += ( i ? ',' + getIndent ( ) : '' ) + s ; i ++ ; } } } ) ; result += getIndent ( - 1 ) + ']' ; refs [ refs . indexOf ( value ) ] = undefined ; return ; } // serialize object if ( isPlainObject ( value ) ) { refs . push ( value ) ; result += '{' + getIndent ( 1 ) ; i = 0 ; Object . getOwnPropertyNames ( value ) . forEach ( function ( k ) { const v = value [ k ] ; if ( Array . isArray ( v ) || isPlainObject ( v ) ) { result += ( i ? ',' + getIndent ( ) : '' ) + JSON . stringify ( k ) + ':' + ( space ? ' ' : '' ) ; doStringify ( value , k , v ) ; i ++ ; } else { const s = toString ( value , k , v ) ; if ( s !== undefined ) { result += ( i ? ',' + getIndent ( ) : '' ) + JSON . stringify ( k ) + ':' + ( space ? ' ' : '' ) + s ; i ++ ; } } } ) ; result += getIndent ( - 1 ) + '}' ; refs [ refs . indexOf ( value ) ] = undefined ; return ; } // serialize values result += toString ( obj , key , value ) ; } ; doStringify ( undefined , undefined , obj ) ; return result ; }
/* putil-stringify
------------------------
(c) 2017-present Panates
SQB may be freely distributed under the MIT license.
For details and documentation:
https://panates.github.io/putil-stringify/
 

@param obj
@param {Function} [replacer]
@param {Number|String} [space]
@return {string}
/ * putil - stringify ------------------------ ( c ) 2017 - present Panates SQB may be freely distributed under the MIT license . For details and documentation : https : // panates . github . io / putil - stringify /