61

I wonder why frameworks/libraries have their own helpers although they exist natively already.

Let's take jQuery and AngularJS. They have their own each iterator functions:

But we have Array.prototype.forEach.

Similarly,

But we have the JSON.parse() function in vanilla JavaScript.

5
  • 75
    As someone who remembers the bad old days of web development, this question makes me cry.
    – josh3736
    Commented Apr 8, 2014 at 3:57
  • 3
    @josh3736 At least you don't still have to support IE6 ('tho, luckily only in a "make it work, it can look like crap" way)
    – Izkata
    Commented Apr 8, 2014 at 19:16
  • 12
    jQuery.each and Array.prototype.forEach are not equivalent.
    – zzzzBov
    Commented Apr 8, 2014 at 21:01
  • 3
    What you should ask yourself is: how much of the functions found in vanillaJS now, originated from toolkits like jQ and the like? The answer is: many. This does beg the question: why are we still using them? Why include jQuery's $.each, and not use the native (and faster) Array.prototype.forEach? Commented Apr 10, 2014 at 14:29
  • 1
    @josh3736 It's ok bro... i.sstatic.net/HJs4V.jpg
    – Crono
    Commented Apr 10, 2014 at 18:47

3 Answers 3

94

Because when those libraries were written, some major browsers did not support those features. Once written and used, these features cannot be removed from these libraries without breaking many applications.

(In this case, "major browser" means a browser that still has large market share, which includes older versions of browsers like Internet Explorer, where large number of users don't necessarily upgrade to the latest version.)

9
  • 44
    $('marquee').each(function() { $(this).append($('<bgsound/>', { src: "good-answer.mp3"} )); }); Commented Apr 8, 2014 at 8:22
  • 37
    @dirkk It's not that recent browsers don't support it. It's that not everyone is lucky enough to have an audience that uses a recent browser. Commented Apr 8, 2014 at 11:17
  • 14
    Array.prototype.forEach iterates only over arrays - both library iterator functions can iterate over arrays or object.
    – JoeG
    Commented Apr 8, 2014 at 12:16
  • 3
    The functions are there to support old browsers and to support old code that calls the library and the programmer doesn't want to rewrite. Even if you've dropped support for IE 6 you probably still have some JavaScript in use written when you did need to support ancient copies of IE. Commented Apr 8, 2014 at 14:19
  • 6
    Many of this functions (e.g. jQuery.parseJSON()) just check if the browser supports it and then sets itself to the browser method, and only uses an alternative on non compatible browsers!
    – Josef
    Commented Apr 9, 2014 at 14:25
35

Because different browsers have different implementations and features baked in their JavaScript engine. The same "vanilla-JS" code could run differently on two different browsers, or even two different versions of the same browser.

The abstraction layer provided by popular JS libraries is a way around this. Behind the scenes, it works around the different browsers capacities and limitations and offers a unified, easy to use API on top of those. This, in turn, allows common operations such as getting a DOM object or fetching JSON data to be consistent, efficient and browser-agnostic.

This makes life a lot easier for developers who can now focus on what code should do, rather than how it should be written to work with browser X or Y.

4
  • 2
    The behavior of "core JS" is well-specified and tested across all browsers.
    – Domenic
    Commented Apr 9, 2014 at 18:32
  • 2
    @Domenic Syntax aside, javascript implementations do differ from browser to browser. There are properties, methods, events and features you will find in just a few browsers only, or even just in one sometimes.
    – Crono
    Commented Apr 9, 2014 at 18:39
  • 1
    Yes, browsers have nonstandard features. That has nothing to do with the standard features discussed in this question.
    – Domenic
    Commented Apr 10, 2014 at 16:54
  • 8
    @Domenic If by "standard features discussed in the question" you mean the Array.prototype.forEach and JSON.parse functions, a quick search on Google will show you that you are wrong. JSON object was not supported on IE7 and forEach wasn't defined on some Opera versions. Libraries such as jQuery however did knew about these limitations and worked around them behind the scenes. So I think my answer does stand.
    – Crono
    Commented Apr 10, 2014 at 17:24
27

1. Backwards compatibility

JavaScript is an implementation of ECMAScript. Most of those functions were introduced in ECMAScript 5 (ES5) however many older browsers which still have a significant enough share of the market do not support these functions (see ECMAScript 5 compatibility table), the most notable of these being IE8.

Generally libraries will revert to the native implementation if it exists otherwise use their own polyfill, for example let's look at AngularJS's implementation (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;
}

The following lines check whether the forEach method exists on the object and whether it is the AngularJS version or not. If not it uses the already specified function (the native version):

} else if (obj.forEach && obj.forEach !== forEach) {
  obj.forEach(iterator, context);
}

2. Convenience

In native JavaScript Array.prototype.forEach is a method exclusive to an instance of Array, however most any Object is iterable too.

For this reason many library creators make their functions polymorphic (able to accept multiple types as input). Let's take the AngularJS code above and see what inputs it accepts:

Functions:

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);
    }
  }

Arrays (with native forEach support):

} else if (obj.forEach && obj.forEach !== forEach) {
  obj.forEach(iterator, context);

Array-like objects including Array (without native forEach support), String, HTMLElement, Object with a valid length property:

} else if (isArrayLike(obj)) {
  for (key = 0; key < obj.length; key++)
    iterator.call(context, obj[key], key);

Objects:

} else {
  for (key in obj) {
    if (obj.hasOwnProperty(key)) {
      iterator.call(context, obj[key], key);
    }
  }
}

Conclusion

As you can see AngularJS will iterate over most any JavaScript Object, although it works in the same way as the native function it accepts far more different types of input and thus is a valid addition to the library as well as a way of bringing ES5 functions to legacy browsers.

1
  • 2
    You may want to update your link to point to a particular commit (e.g. angular.js L203-257) for future reference once master changes.
    – Whymarrh
    Commented Apr 12, 2014 at 0:27

Not the answer you're looking for? Browse other questions tagged or ask your own question.