1.4.0
◀Back | Minified | Changelog | Cautionlog2013-08-24
This update brings a lot of changes, so please have a look at the Cautionlog above to make upgrading a lot less painful!
Also, if you are unable to upgrade, please look here for a patch that will provide better future-proofing for older versions.
Performance Enhancements
By far the biggest change in v1.4 is an across the board look at performance. Some of the more dramatic changes include:
Date#format
up to 21,400% fasterArray#findAll/findIndex/map/any/count/sum
up to 11,270% fasterObject.map
up to 682% fasterArray#min/max/less/more
up to 83% fasterObject.isString/isNumber/isBoolean
up to 77% fasterArray#at
andString#at
up to 242% faster for single index lookups.Range#every
up to 52% faster for dates, 1,500% faster for numbers/strings.String#assign
up to 30% faster.
Although some methods have been given special attention, many of the refactorings were on internal utility methods, which means that the performance enhancements will have a very wide affect. To demonstrate this I looked at simple date creation, an area that on the surface hasn't changed since the last version:
This method, for this format, is now 23% faster thanks to things like speeding up internal type checking etc. Different methods for different cases should also show similar gains.
Natural Sorting
Array sorting using Array#sortBy
now has an added feature to its string collation system which will perform a natural sort by default. This means that if it encounters numeric values it will sort them by their numericality instead of as a string. This means that "25" will be sorted after "7", etc. This option can be set by changing the flag Array.AlphanumericSortNatural
. Additionally, the string collation function itself is now exposed globally as Array.AlphanumericSort
, which means it can be passed directly into Javasript native Array#sort
as well.
Ranges
Ranges were previously a concept that only existed for dates and was a dependency of the Date package. It is now moved out into its own package, simplified, and now works with numbers and strings as well! Syntax for creating a range is the same:
New to ranges is the ability to deal with inverted ranges (a higher number/date can iterate down to a lower one), and the clamp
method which will contain a value to within the range:
The clamp
method as well as cap
(which only limits an upper number) are also now aliases on the numbers:
Additionally, the previous method duration
is now renamed to span
. Finally, Array.create
can understand ranges and convert them to arrays when needed.
Array.find and Array.findIndex
These methods that are defined in the ES6 spec previously existed but worked slightly differently. They have now been aligned with spec and the previous functionality has been moved:
Additionally these methods will act as polyfills, so when they are implemented in later browser versions they will fall back to native implementations. Which brings us to...
Better future-proofing
Sugar previously had a very simple policy. It would never overwrite methods in the global namespace if they were there first. Although this seems to make sense on the surface, it presents a very pernicious problem: if browsers change to add a method that collides, it will effectively overwrite ("underwrite"?) the Sugar implementation. It means that a browser update initiated by the user could potentially cause a script to break.
Of course staying on top of the spec and anticipating such changes is the real name of the game (with the above changes to Array#find
and Array#findIndex
and a couple others, Sugar is now fully in line with the ES6 spec for the foreseeable future). However there may be many reasons that a user can't upgrade, and a browser update should not cause breakages.
For this reason, Sugar has made the reluctant decision to instead default to overriding those methods that it has not deemed polyfills (which it will fall back to, conversely). Although this unfortunately makes Sugar feel less "friendly", real world usage has shown this to be a much better solution. In the end, if a user explicitly includes the Sugar library, they need to be guaranteed that the methods they are expecting will actually be there and not suddenly change.
More natural padding
Previously String#pad
, String#padLeft
, and String#padRight
worked in a rather counter-intuitive manner -- if 20
was passed they would put 20 characters on the ends of the string. They have now changed to be analagous to Number#pad
and will add only enough padding to reach the specified length. If they string is already larger than this length, the method effectively does nothing.
More control over date creation
New to this version is Date.SugarNewDate
. This hook is a way to override the Sugar internal date creation mechanism, which is now consolidated into one place. The common use case for this is timezones. The topic gets a bit complicated -- Javascript dates have no concept of timezones except the one of the current browser locale, which makes having a date in another timezone tricky. Often to get around this dates are created and then shifted to act as though they were in another timezone on the surface (even though the underlying zone is the same). While this method may work, there are many cases when Sugar creates, uses, and disposes of dates before a user can get at them to shift the zone. This often happens in date comparison date.is('the day after tomorrow')
. Date.SugarNewDate
serves as a hook to allow any new date created to pass through this function before being used:
Exposing this as a function gives the user maximum control, allowing even use of full timezone libraries that take into account Daylight Savings Time, etc, for maximum precision:
Other changes
- Added
Function#every
which executes a function everyms
milliseconds or until canceled. - Added
String#truncateOnWords
. Part of theString#truncate
functionality is now here. - Timezone formatting tokens changed to align with Moment.js better.
- Added
Date#beginningOfISOWeek
andDate#endOfISOWeek
- Removed
deep
argument fromObject.fromQueryString
and replaced with optional boolean casting. - Removed
String#normalize
. Object.clone
now only works on known object types and does not work on instances of user-created classes.String#assign
now can be passed an array as well as enumerated arguments.- Fix for
isThisWeek
being false when not"en"
locale. - Fix for
Array#create
not working on argument objects of zero-length (Issue #299). - Fix for
String#capitalize
capitalizing after apostrophes (Issue #325). - Fix for extended objects
select
andreject
returning plain objects. - Fix for
Object.merge
not merging certain deep objects. - Fix for environments where regexes are functions.
- Fix for
Function#cancel
not properly clearing all timers (Issue #346). - Fix for lazy functions not being able to recursively call themselves.
- Added option
immediate
toFunction#lazy
, which is now false by default. - Fixed bug with array like objects iterated over with
loop = true
. - Fixed
String#truncate
not returning primitives. String#repeat
is now aligned more with spec.String#pad
follows suit.