Source: Pool.js

const Pool = ( function(){
	const { setPrototypeOf, defineProperty, getOwnPropertyNames, freeze } = Object,
	 { toString, hasOwnProperty } = {},
	 empty = ( obj, template ) => {
			let templateNames = getOwnPropertyNames( template ),
		 ownNames = getOwnPropertyNames( obj );
			for ( let name of [...templateNames, ...ownNames] ) {
				if( hasOwnProperty.call( template, name ) ) {
					if( typeof template[name] === 'object' ) {
						obj[name] = empty( obj[name], template[name] );
					} else {
						obj[name] = template[name];
					}
				} else {
					delete obj[name];
				}
			}
			return obj;
		},
	 deepFreeze = ( object ) => {
			let propNames = getOwnPropertyNames( object );
			for ( const name of propNames ) {
				let value = object[name];
				object[name] = value && typeof value === 'object' ? deepFreeze( value ) : value;
			}
			return Object.freeze( object );
		},
	 deepClone = ( object ) => {
			let result = {},
				propNames = getOwnPropertyNames( obj );
			for ( let name of propNames ) {
		    let value = object[name];
		    result[name] = value && typeof value === 'object' ? deepClone( value ) : value;
			}
			return setPrototypeOf( result, object.__proto__ );
		};
	/**
	 * An object pool class.
	 * @class
	 */
	class Pool {
		/**
		 * The Pool constructor.
		 * @param {Template} obj The template to use.
		 * @param {number} size The number of objects to create.
		 * @constructs Pool
		 */
		constructor( obj, size ) {
			defineProperty( this, '__default__', {
				value: deepFreeze( deepClone( obj ) ),
				configurable: false,
				protected: true
			} );
			defineProperty( this, '__items__', {
			  value: freeze( setPrototypeOf( Array( size ).fill().map( ( item ) => {
					return [1, deepClone( obj )];
				} ), null ) ),
				configurable: false,
				protected: true
			} );
		}
		/**
		 * Get a new object.
		 * @returns {Object} The new allocated object.
		 */
		allocate() {
			for( let i = 0; i < this.__items__.length; i++ ) {
				let pair = this.__items__[i];
				if( pair[0] === 1 ) {
					pair[0] = 0;
					return pair[1];
				}
			}
		}
		/**
		 * Free an object for later use.
		 * @param {Object} obj The obejct to free.
		 * @returns {undefined}
		 * @throws {Error} The item was not found in the pool.
		 */
		free( obj ) {
			for( let i = 0; i < this.__items__.length; i++ ) {
				let pair = this.__items__[i];
				if( pair[1] === obj ) {
					pair[0] = 1;
					Promise.resolve().then( ()=>{empty( obj, this.__default__ );} );
					return;
				}
			}
			throw Error( 'Object not found in pool.' );
		}
	}
	return Pool;
} )();
/**
 * A template to use for an object pool.
 * @alias Template
 * @typedef {Object} Template
 * @memberof Pool
 */