function structureEquals(structure1, structure2, keys1, keys2, getter,
    traversedValues) {
  if (keys1.length !== keys2.length) {
    return false
  }
  
  traversedValues.set(structure1, structure2)
      
  for (let i = keys1.length; i--;) {
    let key1 = keys1[i]
    let key2 = keys2[i]
    
    if ((key1 instanceof Object) && traversedValues.has(key1)) {
      if (traversedValues.get(key1) !== key2) {
        return false
      } else {
        continue
      }
    }
    
    if (!equals(key1, key2, traversedValues)) {
      return false
    }
    
    if (key1 instanceof Object) {
      traversedValues.set(key1, key2)
    }
    
    let value1 = getter(structure1, key1)
    let value2 = getter(structure2, key2)
    
    if ((value1 instanceof Object) && traversedValues.has(value1)) {
      if (traversedValues.get(value1) !== value2) {
        return false
      } else {
        continue
      }
    }
    
    if (!equals(value1, value2, traversedValues)) {
      return false
    }
    
    if (value1 instanceof Object) {
      traversedValues.set(value1, value2)
    }
  }
  
  return true
}
/**
 * Performs a structured comparison of two structures, determining their
 * equality.
 * 
 * @param {Object} structure1 The first structure to compare.
 * @param {Object} structure2 The second structure to compare.
 * @param {*[]} keys1 The keys of the properties to compare in the first
 *        structure.
 * @param {*[]} keys2 The keys of the properties to compare in the second
 *        structure.
 * @param {function(Object, *): *} getter A callback for retrieving the value
 *        of the property identified by the provided key (2nd argument) from
 *        the structure (1st argument).
 * @param {Map<Object, Object>} traversedValues A map of non-primitive values
 *        traversed in the first structure to their equal counterparts in the
 *        second structure.
 * @return {boolean} {@code true} if the keys, the order of the keys and the
 *         values retrieved by the keys from the structures are equal.
 */
Performs a structured comparison of two structures, determining their
equality.

@param {Object} structure1 The first structure to compare.
@param {Object} structure2 The second structure to compare.
@param {*[]} keys1 The keys of the properties to compare in the first
structure.
@param {*[]} keys2 The keys of the properties to compare in the second
structure.
@param {function(Object, *): *} getter A callback for retrieving the value
of the property identified by the provided key (2nd argument) from
the structure (1st argument).
@param {Map} traversedValues A map of non-primitive values
traversed in the first structure to their equal counterparts in the
second structure.
@return {boolean}  true if the keys, the order of the keys and the
values retrieved by the keys from the structures are equal.
Performs a structured comparison of two structures determining their equality . @param { Object } structure1 The first structure to compare . @param { Object } structure2 The second structure to compare . @param { * [] } keys1 The keys of the properties to compare in the first structure . @param { * [] } keys2 The keys of the properties to compare in the second structure . @param { function ( Object * ) : * } getter A callback for retrieving the value of the property identified by the provided key ( 2nd argument ) from the structure ( 1st argument ) . @param { Map } traversedValues A map of non - primitive values traversed in the first structure to their equal counterparts in the second structure . @return { boolean } true if the keys the order of the keys and the values retrieved by the keys from the structures are equal .
function structureEquals(structure1, structure2, keys1, keys2, getter,
    traversedValues) {
  if (keys1.length !== keys2.length) {
    return false
  }
  traversedValues.set(structure1, structure2)
  for (let i = keys1.length; i--;) {
    let key1 = keys1[i]
    let key2 = keys2[i]
    if ((key1 instanceof Object) && traversedValues.has(key1)) {
      if (traversedValues.get(key1) !== key2) {
        return false
      } else {
        continue
      }
    }
    if (!equals(key1, key2, traversedValues)) {
      return false
    }
    if (key1 instanceof Object) {
      traversedValues.set(key1, key2)
    }
    let value1 = getter(structure1, key1)
    let value2 = getter(structure2, key2)
    if ((value1 instanceof Object) && traversedValues.has(value1)) {
      if (traversedValues.get(value1) !== value2) {
        return false
      } else {
        continue
      }
    }
    if (!equals(value1, value2, traversedValues)) {
      return false
    }
    if (value1 instanceof Object) {
      traversedValues.set(value1, value2)
    }
  }
  return true
}
function structureEquals ( structure1 , structure2 , keys1 , keys2 , getter , traversedValues ) { if ( keys1 . length !== keys2 . length ) { return false } traversedValues . set ( structure1 , structure2 ) for ( let i = keys1 . length ; i -- ; ) { let key1 = keys1 [ i ] let key2 = keys2 [ i ] if ( ( key1 instanceof Object ) && traversedValues . has ( key1 ) ) { if ( traversedValues . get ( key1 ) !== key2 ) { return false } else { continue } } if ( ! equals ( key1 , key2 , traversedValues ) ) { return false } if ( key1 instanceof Object ) { traversedValues . set ( key1 , key2 ) } let value1 = getter ( structure1 , key1 ) let value2 = getter ( structure2 , key2 ) if ( ( value1 instanceof Object ) && traversedValues . has ( value1 ) ) { if ( traversedValues . get ( value1 ) !== value2 ) { return false } else { continue } } if ( ! equals ( value1 , value2 , traversedValues ) ) { return false } if ( value1 instanceof Object ) { traversedValues . set ( value1 , value2 ) } } return true }
Performs a structured comparison of two structures, determining their
 equality.
Performs a structured comparison of two structures determining their equality .