Q32: What edge cases should you consider when writing JavaScript polyfills?
Answer
A polyfill that works for a simple example may still behave differently from the native API. Interviewers often test whether a candidate considers edge cases and specification behavior.
Important considerations
- Nullish receivers: Methods such as
map()andcall()must handle invalid receivers according to the specification. - Callback validation: Array iteration methods should throw a
TypeErrorif the callback is not callable. - Sparse arrays: Some methods skip holes, while methods such as
find()visit them asundefined. - Initial values:
reduce()behaves differently when no initial accumulator is provided. - Callback arguments: Array iteration callbacks generally receive the value, index, and original object.
- thisArg: Methods that accept a
thisArgmust preserve its specified behavior. - Short-circuiting:
some(),every(), andfind()stop when their result is determined. - Promise ordering: Promise combinators preserve input order in their results, even when inputs settle in another order.
- Symbols and descriptors: Object utilities may need to account for symbol keys and property enumerability.
- Iterables and array-like objects: These are distinct concepts and should not be treated interchangeably.
- Native method semantics: Strict mode, constructor calls, coercion, exceptions, and exotic objects can affect behavior.
- Prototype pollution: Adding properties to built-in prototypes can conflict with other code. Prefer a separate utility function when prototype modification is not required.
Best practice
Use feature detection when a polyfill must provide missing browser functionality. Avoid overwriting an existing native method without a compelling reason. For learning exercises, use names such as myMap or myBind so the native methods remain available for comparison.
For production use, prefer established polyfill libraries or thoroughly tested implementations when exact compatibility matters.
Key Takeaways
- A robust polyfill must account for edge cases and native specification semantics.
- Avoid replacing native methods unnecessarily, and test sparse arrays, errors, symbols, and asynchronous behavior.