// copy-on-set function Cos(state, parent) { 'use strict'; if (typeof this === 'undefined') { return new Cos(state, parent); } state = state || {}; let copied = false; this.get = name => state[name]; this.set = (name, value) => { if (!copied) { state = copy(state); } state[name] = value; }; this.spawn = () => new Cos(state, this); this.state = () => state; this.parent = () => parent; } // deap copy function copy(obj) { if (obj === null || typeof obj !== 'object') { // primitive types are passed by value return obj; } if (Array.isArray(obj)) { // copy array return obj.map(item => copy(item)); } if (obj instanceof Date) { // copy date return new Date(obj.getTime()); } // copy object return Object.keys(obj).reduce((obj, item) => obj[item] = copy(obj[item]) && obj, Object.assign({}, obj)); }