1. Compatibilidade com versões anteriores
JavaScript é uma implementação do ECMAScript . A maioria dessas funções foi introduzida no ECMAScript 5 (ES5); no entanto, muitos navegadores mais antigos que ainda possuem uma participação significativa no mercado não suportam essas funções (consulte a tabela de compatibilidade do ECMAScript 5 ), sendo o IE8 o mais notável.
Geralmente as bibliotecas reverterão para a implementação nativa, se existir, caso contrário, use seu próprio polyfill; por exemplo, vejamos a implementação do AngularJS ( angular.js L203-257 ):
function forEach(obj, iterator, context) {
var key;
if (obj) {
if (isFunction(obj)){
for (key in obj) {
// Need to check if hasOwnProperty exists,
// as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
iterator.call(context, obj[key], key);
}
}
} else if (obj.forEach && obj.forEach !== forEach) {
obj.forEach(iterator, context);
} else if (isArrayLike(obj)) {
for (key = 0; key < obj.length; key++)
iterator.call(context, obj[key], key);
} else {
for (key in obj) {
if (obj.hasOwnProperty(key)) {
iterator.call(context, obj[key], key);
}
}
}
}
return obj;
}
As linhas a seguir verificam se o forEachmétodo existe no objeto e se é a versão do AngularJS ou não. Caso contrário, ele usa a função já especificada (a versão nativa):
} else if (obj.forEach && obj.forEach !== forEach) {
obj.forEach(iterator, context);
}
2. Conveniência
No JavaScript nativo, Array.prototype.forEaché um método exclusivo para uma instância de Array, no entanto, quase todos também Objectsão iteráveis.
Por esse motivo, muitos criadores de bibliotecas tornam suas funções polimórficas (capazes de aceitar vários tipos como entrada). Vamos pegar o código AngularJS acima e ver quais entradas ele aceita:
Funções :
if (isFunction(obj)){
for (key in obj) {
// Need to check if hasOwnProperty exists,
// as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
iterator.call(context, obj[key], key);
}
}
Matrizes (com suporte nativo para cada um):
} else if (obj.forEach && obj.forEach !== forEach) {
obj.forEach(iterator, context);
Objetos semelhantes a matrizes, incluindo Matriz (sem suporte nativo para Cada), String, HTMLElement, Objeto com uma propriedade de comprimento válida:
} else if (isArrayLike(obj)) {
for (key = 0; key < obj.length; key++)
iterator.call(context, obj[key], key);
Objetos:
} else {
for (key in obj) {
if (obj.hasOwnProperty(key)) {
iterator.call(context, obj[key], key);
}
}
}
Conclusão
Como você pode ver, o AngularJS itera sobre a maioria dos objetos JavaScript, embora funcione da mesma maneira que a função nativa, aceita tipos de entrada muito mais diferentes e, portanto, é uma adição válida à biblioteca e também uma maneira de trazer funções ES5 para navegadores herdados.