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 forEach
mé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 Object
sã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.