utils.js: significant modification of diff behavior

I think it's better, anyway.  I was becoming frustrated by seeing my `Date`s and `Function`s represented as objects within the diffs.  Even more frustrating is when the diff result *appears to be exactly the same* but the assertion failed anyway.  So this is my attempt at making the diffs more friendly and understandable.

Summary of changes:

- Added inner function `emptyRepresentation()`, which is called in the case that your `Object`, `Function` or `Array` has nothing "in" it.  It attempts to make a unique representation of that empty value.
- Added private API function `exports.type()`, which can be used to deduce the type of any given value.  *I exported this function mainly for testing purposes*
- Modified `exports.stringify()` to avoid `JSON.stringify()` in circumstances where `JSON.stringify()` may not be much help.  My only concern here is whether or not we should display a string in double-quotes, as to coincide with `JSON.stringify()` behavior.
  - If `value` is `undefined` or `null`, return `'[undefined]'` or `'[null]'`, respectively.   *It's possible to have strings with these same values, which may lead to confusion, but this is an edge case.*
  - If `value` is not an `Object`, `Function` or `Array`, return result of `value.toString()`.
  - If `value` is an *empty* `Object`, `Function` or `Array`, return result of function `emptyRepresentation()`.
  - If `value` has properties, call {@link exports.canonicalize} on it, then return result of `JSON.stringify()`.
- Modified `exports.canonicalize()` to support the above strategy, with a couple slight differences.  The strategy is as follows.  If the value...
  - has already been seen, return string `'[Circular]'`
  - is `undefined`, return string `'[undefined]'`
  - is `null`, return value `null`.  This differs from the `stringify()` behavior, as to provide a valid JSON representation.
  - is not an `Array`, `Object`, or `Function`, return the value of the Thing's `toString()` method
  - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again.
  - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()`
- Added many tests