1. Compatibilidade retroativa
O 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 têm uma fatia significativa do mercado não suportam essas funções (veja tabela de compatibilidade ECMAScript 5 ), sendo as mais notáveis o IE8.
Geralmente, as bibliotecas serão revertidas para a implementação nativa, se existirem. Caso contrário, use seu próprio polyfill, por exemplo, vamos analisar 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 método forEach
existe no objeto e se é a versão do AngularJS ou não. Se não, 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
, mas a maioria dos Object
também é iterável.
Por esse motivo, muitos criadores de bibliotecas tornam suas funções polimórficas (capazes de aceitar vários tipos de 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 paraEach):
} else if (obj.forEach && obj.forEach !== forEach) {
obj.forEach(iterator, context);
Objetos semelhantes a matrizes incluindo Array (sem suporte nativo a for each), String, HTMLElement, Object com uma propriedade de tamanho 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 iterará praticamente qualquer objeto JavaScript, embora funcione da mesma forma que a função nativa, ele aceita muito mais tipos diferentes de entrada e, portanto, é uma adição válida à biblioteca, bem como uma maneira de trazendo funções ES5 para navegadores legados.