Skip to content

Underscore.js Differences

_.m aims to be as compatible with Underscore.js as possible, but some differences exist due to language differences between JavaScript and Objective-C.

The following Underscore.js functions are not available in _.m:

FunctionReason
bindObjective-C blocks capture scope automatically
bindAllNot applicable
isElementNo DOM in Objective-C
isRegExpDifferent regex API
isUndefinedObjective-C has nil instead
noConflictNot applicable
mixinDifferent extension model
escapeDifferent string escaping needs
templateDifferent templating approach

In Underscore.js, many functions accept an optional context parameter:

// JavaScript
_.each(list, iterator, context);

In _.m, blocks automatically capture their surrounding scope, so context is not needed:

// Objective-C - context captured automatically
__weak typeof(self) weakSelf = self;
_.each(list, ^(id item, ...) {
[weakSelf doSomething:item];
});
JavaScriptObjective-C
undefinednil
nullnil or [NSNull null]
ArrayNSArray
ObjectNSDictionary
FunctionBlock (^)

_.m uses ... (va_list) for optional iterator arguments:

// Block signature includes ... for optional key and list
_.each(list, ^(id value, ...) {
// Access optional args via va_list if needed
});

_.m provides macros for extracting variable arguments in blocks:

Collection Iteration (no terminators needed)

Section titled “Collection Iteration (no terminators needed)”
MacroDescription
ARGS_KEY(value)Extracts the key (second argument)
ARGS_INDEX(value)Extracts the index (second argument)
ARGS_LIST(value, LIST_NAME)Extracts the list (third argument)
MacroDescription
ARGS_AO(NAME, lastNamedArg)Collects all id objects after the specified argument (nil-terminated)
ARGS_AI(NAME, lastNamedArg)Collects all integers after the specified argument (AI_END-terminated)
MacroDescription
ARG_B()Extract one BOOL
ARG_I()Extract one NSInteger
ARG_UI()Extract one NSUInteger
ARG_F()Extract one float
ARG_D()Extract one double
ARG_N()Extract one NSNumber*
ARG_NSO()Extract one NSObject*

_.m defines block types for consistency:

Block TypeSignatureUsage
_EachBlock^(id value, ...)Iteration without return
_EachWithStopBlock^B(id value, ...)Returns boolean to control loop
_MapBlock^id(id value, ...)Returns transformed value
_ReduceBlock^id(id memo, id value, ...)Accumulation function
_FindBlock^B(id value)Predicate for finding
_ItemTestBlock^B(id value, ...)Predicate for filtering
_MaxBlock / _MinBlock^id(id value)Comparison function
_SortByBlock^id(id value, ...)Returns sort key
_GroupByBlock^id(id value, ...)Returns grouping key
_DelayBlock / _DeferBlock^()No arguments, no return
_ThrottleBlock^id()Returns id
_DebounceBlock^(id arg1, ...)Variable arguments
_OnceBlock^id(id arg1, ...)Execute once
_AfterBlock^id(id arg1, ...)Execute after N calls
_WrapBlock^id(_WrappedBlock wrapped, id arg1, ...)Wraps another block
_ComposeBlock^id(id arg1, ...)Function composition
_TapBlock^(id obj)Side-effect interceptor
_TimesBlock^(I index)Iteration N times
_IdentityBlock^id(id value)Returns unchanged value

_.m is fully ARC compatible. When capturing self in blocks, use __weak to avoid retain cycles:

__weak typeof(self) weakSelf = self;
_.each(items, ^(id item, ...) {
[weakSelf processItem:item];
});

_.m provides shorthand type aliases for cleaner code:

// Instead of
NSArray* result = ...;
NSDictionary* dict = ...;
// Use
A* result = ...;
O* dict = ...;

See the Introduction for the full list of type shortcuts.