Script Preparation code:
x
 
var obj = {};
for (i = 1000; i > 0; i--) {
  if (i%2 == 0) {
    obj[i] = 'String';
  } else {
    obj[i] = [ 'Array of String', 'Array of String' ];
  }
}
Tests:
  • forEach

     
    function ClassList(collection={}) {
        const classNames = {};
        const keys = Object.keys(collection);
        keys.forEach((key) => {
            const innerCollection = collection[key];
            const collectionCheck = Object.prototype.toString.call(innerCollection);
            switch (collectionCheck) {
            case '[object Object]': {
                const innerKeys = Object.keys(innerCollection);
                if (innerKeys.length === 0) {
                    classNames[key] = '';
                    break;
                }
                let classList = [];
                innerKeys.forEach((innerKey) => {
                    if (!innerCollection[innerKey] || !innerCollection[innerKey].length) {
                        return;
                    }
                    const innerCollectionCheck = Object.prototype.toString.call(innerCollection[innerKey]);
                    switch (innerCollectionCheck) {
                    case '[object Array]':
                        classList.push(...innerCollection[innerKey]);
                        break;
                    case '[object String]':
                        classList.push(innerCollection[innerKey]);
                        break;
                    }
                });
                classNames[key] = classList.reduce((acc, cl) => (acc += cl + ' '), '');
                break;
            }
            case '[object Array]':
                classNames[key] = innerCollection.reduce((acc, cl) => (acc += cl + ' '), '');
                break;
            case '[object String]':
                classNames[key] = innerCollection;
                break;
            }
        });
        return classNames;
    }
    ClassList( obj );
  • Recursive outer

     
    function rec(classList, key, collection = {} ) {
        return Object.values( collection ).reduce( (acc, col) => {        
            const colCheck = Object.prototype.toString.call(col);
            switch (colCheck) {
            case '[object Object]': {
                if ( Object.keys(col).length === 0 ) {
                    acc[key] = '';
                    break;
                }
                rec(classList, key, col );
                break;
            }
        
            case '[object Array]':
                acc[key] += col.join(' ') + ' ';
                break;
        
            case '[object String]':
                acc[key] += col + ' ';
                break;
            }
            return acc;
        }, classList );
    }
    function ClassList(collection = {}) {
        const keys = Object.keys(collection);
        
        return keys.reduce( (classList, key) => {
            switch (Object.prototype.toString.call(collection[key]) ) {
            case '[object Object]': {
                classList[key] = '';
                if ( Object.keys(collection[key]).length === 0 ) {
                    break;
                }
                rec(classList, key, collection[key] );
                break;
            }
        
            case '[object Array]':
                classList[key] = collection[key].join(' ') + ' ';
                break;
        
            case '[object String]':
                classList[key] = collection[key] + ' ';
                break;
            }
            return classList;
        }, {} );
    }
    ClassList( obj );
  • Recursive flatten

     
    function ClassList(collection = {}) {
        const result = {};
        function flatten(node, str) {
            const nodeType = Object.prototype.toString.call(node);
            
            switch (nodeType) {
                case '[object String]': {
                    str += node + ' ';
                    break;
                }
                case '[object Array]': {
                    str += node.join(' ') + ' ';
                    break;
                }
                case '[object Object]': {
                    for (const key in node) {
                        str += flatten(node[key], '');
                    }
                    break;
                }
            }
            
            return str;
        }
        for (const key in collection) {
            result[key] = flatten(collection[key], '').trimEnd();
        }
        return result;
    }
    ClassList(obj);
Rendered benchmark preparation results:

Suite status: <idle, ready to run>

Previous results

Experimental features:

  • Test case name Result
    forEach
    Recursive outer
    Recursive flatten

    Fastest: N/A

    Slowest: N/A

Latest run results:
Run details: (Test run date: 4 years ago)
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1.2 Safari/605.1.15
Safari 13 on Mac OS X 10.15.6
View result in a separate tab
Test name Executions per second
forEach 2038.1 Ops/sec
Recursive outer 1353.2 Ops/sec
Recursive flatten 1549.7 Ops/sec