HTML Preparation code:
AخA
 
1
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.2/immutable.min.js"></script>
2
<script src="https://cdn.jsdelivr.net/npm/immutability-helper@2.7.0/index.min.js"></script>
Tests:
  • object spread

    x
     
    const obj = {};
    for(i=0;i<100000;i++){
      obj[i] = 'some long string which will need to be copied';
    }
    const obj2 = {key: 'This is final object'}
    const final = {obj2, ...obj};
  • object assign

     
    const obj = {};
    for(i=0;i<100000;i++){
      obj[i] = 'some long string which will need to be copied';
    }
    const obj2 = {key: 'This is final object'}
    const final = Object.assign({}, obj2, obj)
  • immutable-js

     
    const obj = {};
    for(i=0;i<100000;i++){
      obj[i] = 'some long string which will need to be copied';
    }
    const immObj = Immutable.Map();
    const obj2 = {key: 'This is final object'}
    const final = immObj.set(obj2);
  • immutability-helper

     
    var hasOwnProperty = Object.prototype.hasOwnProperty;
    var splice = Array.prototype.splice;
    var toString = Object.prototype.toString
    var type = function(obj) {
      return toString.call(obj).slice(8, -1);
    }
    var assign = Object.assign || /* istanbul ignore next */ function assign(target, source) {
      getAllKeys(source).forEach(function(key) {
        if (hasOwnProperty.call(source, key)) {
          target[key] = source[key];
        }
      });
      return target;
    };
    var getAllKeys = typeof Object.getOwnPropertySymbols === 'function' ?
      function(obj) { return Object.keys(obj).concat(Object.getOwnPropertySymbols(obj)) } :
      /* istanbul ignore next */ function(obj) { return Object.keys(obj) };
    /* istanbul ignore next */
    function copy(object) {
      if (Array.isArray(object)) {
        return assign(object.constructor(object.length), object)
      } else if (type(object) === 'Map') {
        return new Map(object)
      } else if (type(object) === 'Set') {
        return new Set(object)
      } else if (object && typeof object === 'object') {
        var prototype = object.constructor && object.constructor.prototype
        return assign(Object.create(prototype || null), object);
      } else {
        return object;
      }
    }
    function newContext() {
      var commands = assign({}, defaultCommands);
      update.extend = function(directive, fn) {
        commands[directive] = fn;
      };
      update.isEquals = function(a, b) { return a === b; };
      return update;
      function update(object, spec) {
        if (typeof spec === 'function') {
          return spec(object);
        }
        if (!(Array.isArray(object) && Array.isArray(spec))) {
          
        }
       
        var nextObject = object;
        var index, key;
        getAllKeys(spec).forEach(function(key) {
          if (hasOwnProperty.call(commands, key)) {
            var objectWasNextObject = object === nextObject;
            nextObject = commands[key](spec[key], nextObject, spec, object);
            if (objectWasNextObject && update.isEquals(nextObject, object)) {
              nextObject = object;
            }
          } else {
            var nextValueForKey =
              type(object) === 'Map'
                ? update(object.get(key), spec[key])
                : update(object[key], spec[key]);
            if (!update.isEquals(nextValueForKey, nextObject[key]) || typeof nextValueForKey === 'undefined' && !hasOwnProperty.call(object, key)) {
              if (nextObject === object) {
                nextObject = copy(object);
              }
              if (type(nextObject) === 'Map') {
                nextObject.set(key, nextValueForKey);
              } else {
                nextObject[key] = nextValueForKey;
              }
            }
          }
        })
        return nextObject;
      }
    }
    var defaultCommands = {
      $push: function(value, nextObject, spec) {
      
        return value.length ? nextObject.concat(value) : nextObject;
      },
      $unshift: function(value, nextObject, spec) {
        // invariantPushAndUnshift(nextObject, spec, '$unshift');
        return value.length ? value.concat(nextObject) : nextObject;
      },
      $splice: function(value, nextObject, spec, originalObject) {
        // invariantSplices(nextObject, spec);
        value.forEach(function(args) {
        //   invariantSplice(args);
          if (nextObject === originalObject && args.length) nextObject = copy(originalObject);
          splice.apply(nextObject, args);
        });
        return nextObject;
      },
      $set: function(value, nextObject, spec) {
        // invariantSet(spec);
        return value;
      },
      $toggle: function(targets, nextObject) {
        // invariantSpecArray(targets, '$toggle');
        var nextObjectCopy = targets.length ? copy(nextObject) : nextObject;
        targets.forEach(function(target) {
          nextObjectCopy[target] = !nextObject[target];
        });
        return nextObjectCopy;
      },
      $unset: function(value, nextObject, spec, originalObject) {
        // invariantSpecArray(value, '$unset');
        value.forEach(function(key) {
          if (Object.hasOwnProperty.call(nextObject, key)) {
            if (nextObject === originalObject) nextObject = copy(originalObject);
            delete nextObject[key];
          }
        });
        return nextObject;
      },
      $add: function(value, nextObject, spec, originalObject) {
        // invariantMapOrSet(nextObject, '$add');
        // invariantSpecArray(value, '$add');
        if (type(nextObject) === 'Map') {
          value.forEach(function(pair) {
            var key = pair[0];
            var value = pair[1];
            if (nextObject === originalObject && nextObject.get(key) !== value) nextObject = copy(originalObject);
            nextObject.set(key, value);
          });
        } else {
          value.forEach(function(value) {
            if (nextObject === originalObject && !nextObject.has(value)) nextObject = copy(originalObject);
            nextObject.add(value);
          });
        }
        return nextObject;
      },
      $remove: function(value, nextObject, spec, originalObject) {
        // invariantMapOrSet(nextObject, '$remove');
        // invariantSpecArray(value, '$remove');
        value.forEach(function(key) {
          if (nextObject === originalObject && nextObject.has(key)) nextObject = copy(originalObject);
          nextObject.delete(key);
        });
        return nextObject;
      },
      $merge: function(value, nextObject, spec, originalObject) {
        // invariantMerge(nextObject, value);
        getAllKeys(value).forEach(function(key) {
          if (value[key] !== nextObject[key]) {
            if (nextObject === originalObject) nextObject = copy(originalObject);
            nextObject[key] = value[key];
          }
        });
        return nextObject;
      },
      $apply: function(value, original) {
        // invariantApply(value);
        return value(original);
      }
    };
    var contextForExport = newContext();
    const obj = {};
    for(i=0;i<100000;i++){
      obj[i] = 'some long string which will need to be copied';
    }
    const obj2 = {key: 'This is final object'}
    const final = contextForExport(obj2, {$merge: obj});
Rendered benchmark preparation results:

Suite status: <idle, ready to run>

Previous results

Experimental features:

  • Test case name Result
    object spread
    object assign
    immutable-js
    immutability-helper

    Fastest: N/A

    Slowest: N/A

Latest run results:
Run details: (Test run date: 7 months ago)
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
Chrome 128 on Mac OS X 10.15.7
View result in a separate tab
Test name Executions per second
object spread 103.1 Ops/sec
object assign 105.3 Ops/sec
immutable-js 1612.0 Ops/sec
immutability-helper 237.9 Ops/sec