function deepEqual( a, b ) {
	var aKeys;
	var bKeys;
	var typeA;
	var typeB;
	var key;
	var i;

	typeA = typeof a;
	typeB = typeof b;
	if ( a === null || typeA !== 'object' ) {
		if ( b === null || typeB !== 'object' ) {
			return a === b;
		}
		return false;
	}
	// Case: `a` is of type 'object'
	if ( typeB !== 'object' ) {
		return false;
	}
	if ( getPrototypeOf( a ) !== getPrototypeOf( b ) ) {
		return false;
	}
	if ( isDate( a ) ) {
		return a.getTime() === b.getTime();
	}
	if ( isRegExp( a ) ) {
		return a.source === b.source && a.flags === b.flags;
	}
	if ( isError( a ) ) {
		if ( a.message !== b.message || a.name !== b.name ) {
			return false;
		}
	}
	if ( isBuffer( a ) ) {
		if ( a.length !== b.length ) {
			return false;
		}
		for ( i = 0; i < a.length; i++ ) {
			if ( a[ i ] !== b[ i ] ) {
				return false;
			}
		}
		return true;
	}
	aKeys = objectKeys( a );
	bKeys = objectKeys( b );
	if ( aKeys.length !== bKeys.length ) {
		return false;
	}
	aKeys.sort();
	bKeys.sort();

	// Cheap key test:
	for ( i = 0; i < aKeys.length; i++ ) {
		if ( aKeys[ i ] !== bKeys[ i ] ) {
			return false;
		}
	}
	// Possibly expensive deep equality test for each corresponding key:
	for ( i = 0; i < aKeys.length; i++ ) {
		key = aKeys[ i ];
		if ( !deepEqual( a[ key ], b[ key ] ) ) {
			return false;
		}
	}
	return typeA === typeB;
}
Tests for deep equality between two values.

@param {*} a - first comparison value
@param {*} b - second comparison value
@returns {boolean} boolean indicating if `a` is deep equal to `b`

@example
var bool = deepEqual( [ 1, 2, 3 ], [ 1, 2, 3 ] );
// returns true

@example
var bool = deepEqual( [ 1, 2, 3 ], [ 1, 2, '3' ] );
// returns false

@example
var bool = deepEqual( { 'a': 2 }, { 'a': [ 2 ] } );
// returns false

@example
var bool = deepEqual( [], {} );
// returns false

@example
var bool = deepEqual( null, null );
// returns true