Zepto implements a set of lightweight, purpose-built utility functions to handle common operations on arrays, strings, and JavaScript types—without relying on external dependencies or heavy abstractions. These helpers form the foundation for higher-level APIs and reflect thoughtful design choices around browser compatibility, performance, and edge-case handling.
Array Utilities
Zepto begins by caching native array methods to avoid repeated property lookups:
const EMPTY_ARRAY = [];
const arrayConcat = EMPTY_ARRAY.concat;
const arrayFilter = EMPTY_ARRAY.filter;
const arraySlice = EMPTY_ARRAY.slice;
compact()
Removes falsy values equivalent to null or undefined:
function compact(input) {
return arrayFilter.call(input, item => item != null);
}
This leverages loose equality (!=) so both null and undefined coerce to false and are filtered out. Strict comparison (!==) would require explicit checks for both values.
flatten()
Performs single-level flattening—only unwraps immediate nested arrays:
function flatten(input) {
return input.length ? arrayConcat.apply([], input) : input;
}
The use of apply spreads the input array as individual arguments to concat, effectively merging top-level elements: [1, [2, 3], 4] → [1, 2, 3, 4]. Deep nesting like [1, [[2]]] remains unchanged.
uniq()
Removes duplicate entries while preserving order:
function uniq(input) {
return arrayFilter.call(input, (item, index) => input.indexOf(item) === index);
}
An element is retained only if its first occurrence in the array matches its current position—ensuring uniqueness without side effects or external state.
String Transformations
camelize()
Converts kebab-case strings into camelCase:
function camelize(str) {
return str.replace(/-+(.)/g, (_, char) => char ? char.toUpperCase() : '');
}
The regex matches one or more hyphens followed by any character; that character is capitalized and the hyphens omitted. For example, "data-user-id" becomes "dataUserId".
dasherize()
Converts PascalCase or mixed-case identifiers into lowercase kebab-case:
function dasherize(str) {
return str
.replace(/::/g, '/')
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
.replace(/([a-z\d])([A-Z])/g, '$1_$2')
.replace(/_/g, '-')
.toLowerCase();
}
Each step progressively inserts underscores before capitol letters (accounting for acronyms and transitions), then replaces underscores with hyphens and lowercaess everything. Input "XMLHttpRequest" yields "x-m-l-http-request".
Type Detection System
Zepto avoids typeof’s limitations (e.g., typeof [] === "object") by using Object.prototype.toString for precise classification:
const TYPE_MAP = Object.create(null);
const toString = Object.prototype.toString;
'Boolean Number String Function Array Date RegExp Object Error'.split(' ').forEach(name => {
TYPE_MAP[`[object ${name}]`] = name.toLowerCase();
});
type()
Returns a normalized lowercase type string:
function type(value) {
return value == null ? String(value) : TYPE_MAP[toString.call(value)] || 'object';
}
Handles null and undefined explicitly (returning "null" or "undefined"), otherwise delegates to the map. Fallback to "object" covers host objects and unrecognized natives.
Helper Predicates
Derived from type():
function isFunction(val) { return type(val) === 'function'; }
function isObject(val) { return type(val) === 'object'; }
function isWindow(val) { return val != null && val === val.window; }
function isDocument(val) { return val != null && val.nodeType === 9; }
function isPlainObject(val) {
return isObject(val) && !isWindow(val) && Object.getPrototypeOf(val) === Object.prototype;
}
Note: isDocument relies on DOCUMENT_NODE === 9, per DOM specification.
isArray()
Uses feature detection with graceful fallback:
const isArray = Array.isArray || (val => toString.call(val) === '[object Array]');
Unlike instanceof Array, this approach works across frames and execution contexts because toString is deterministic and environment-agnostic.
likeArray()
Determines whether an object resembles an array—supporting iteration and length-based access:
function likeArray(obj) {
const len = obj && 'length' in obj ? obj.length : 0;
const t = type(obj);
return t !== 'function' &&
!isWindow(obj) &&
(t === 'array' || len === 0 || (
typeof len === 'number' &&
len > 0 &&
(len - 1) in obj
));
}
A "like-array" must have a numeric length, support bracket notation up to length - 1, and not be a function or window. This enables uniform handling of arguments, DOM collections, and custom array-like structures.