Dlaczego frameworki / biblioteki JavaScript mają funkcje, które już istnieją w czystym JavaScript?

60

Zastanawiam się, dlaczego frameworki / biblioteki mają własnych pomocników, chociaż istnieją już natywnie.

Weźmy jQuery i AngularJS . Mają własne eachfunkcje iteracyjne:

Ale my mamy Array.prototype.forEach.

Podobnie,

Ale mamy JSON.parse()funkcję w waniliowym JavaScript.

Cihad Turhan
źródło
75
Jako ktoś, kto pamięta stare, złe czasy tworzenia stron internetowych, to pytanie sprawia, że ​​płaczę.
josh3736
3
@ josh3736 Przynajmniej nie musisz jeszcze obsługiwać IE6 („na szczęście tylko w sposób„
spraw,
12
jQuery.eachi Array.prototype.forEachnie są równoważne.
zzzzBov
3
To, co powinieneś sobie zadać, to: ile funkcji dostępnych obecnie w vanillaJS pochodzi z zestawów narzędzi takich jak jQ i tym podobne? Odpowiedź brzmi: wiele . To nasuwa pytanie: dlaczego nadal ich używamy? Dlaczego warto uwzględniać jQuery $.each, a nie używać natywnego (i szybszego) Array.prototype.forEach?
Elias Van Ootegem,
1
@ josh3736 It's ok bro ... i.stack.imgur.com/HJs4V.jpg
Crono

Odpowiedzi:

93

Ponieważ kiedy te biblioteki zostały napisane, niektóre główne przeglądarki nie obsługiwały tych funkcji. Po napisaniu i użyciu tych funkcji nie można usunąć z tych bibliotek bez uszkodzenia wielu aplikacji.

(W tym przypadku „główna przeglądarka” oznacza przeglądarkę, która nadal ma duży udział w rynku, w tym starsze wersje przeglądarek, takie jak Internet Explorer, w których duża liczba użytkowników niekoniecznie aktualizuje się do najnowszej wersji).

Gort the Robot
źródło
44
$ ('marquee'). each (function () {$ (this) .append ($ ('<bgsound />', {src: "good-answer.mp3"}));});
Pierre Arlaud,
36
@dirkk To nie jest tak, że najnowsze przeglądarki go nie obsługują. Chodzi o to, że nie wszyscy mają szczęście mieć odbiorców, którzy korzystają z najnowszej przeglądarki.
George Reith,
14
Array.prototype.forEachiteruje tylko na tablicach - obie funkcje iteratora bibliotek mogą iterować na tablicach lub obiektach.
JoeG
3
Funkcje służą do obsługi starych przeglądarek i obsługi starego kodu, który wywołuje bibliotekę, a programista nie chce przepisywać. Nawet jeśli zrezygnowałeś z obsługi IE 6, prawdopodobnie nadal używasz JavaScript w użyciu, gdy trzeba było obsługiwać starożytne kopie IE.
Michael Shopsin
6
Wiele z tych funkcji (np. JQuery.parseJSON ()) po prostu sprawdza, czy przeglądarka obsługuje tę funkcję, a następnie ustawia się na metodę przeglądarki i używa alternatywy tylko w niekompatybilnych przeglądarkach!
Josef
35

Ponieważ różne przeglądarki mają różne implementacje i funkcje zapisane w silniku JavaScript. Ten sam kod „waniliowy-JS” może działać inaczej w dwóch różnych przeglądarkach, a nawet w dwóch różnych wersjach tej samej przeglądarki.

Warstwa abstrakcji udostępniana przez popularne biblioteki JS stanowi obejście tego problemu. Za kulisami działa wokół różnych możliwości i ograniczeń przeglądarek i oferuje zunifikowany, łatwy w użyciu interfejs API. To z kolei pozwala na zachowanie spójności, wydajności i niezależności przeglądarki od typowych operacji, takich jak uzyskiwanie obiektu DOM lub pobieranie danych JSON.

To znacznie ułatwia życie programistom, którzy mogą teraz skupić się na tym, co powinien zrobić kod, a nie na tym, jak powinien być napisany do pracy z przeglądarką X lub Y.

Crono
źródło
2
Zachowanie „podstawowego JS” jest dobrze określone i przetestowane we wszystkich przeglądarkach.
Domenic
2
@ Pomijając składnię, implementacje javascript różnią się w zależności od przeglądarki. Istnieją właściwości, metody, zdarzenia i funkcje, które można znaleźć tylko w kilku przeglądarkach, a czasem tylko w jednej.
Crono
1
Tak, przeglądarki mają niestandardowe funkcje. Nie ma to nic wspólnego ze standardowymi funkcjami omówionymi w tym pytaniu.
Domenic
8
@Domenic Jeśli przez „standardowe funkcje omówione w pytaniu” masz na myśli funkcje Array.prototype.forEachi JSON.parse, szybkie wyszukiwanie w Google pokaże ci, że się mylisz. JSONobiekt nie był obsługiwany w IE7 i forEachnie był zdefiniowany w niektórych wersjach Opery. Biblioteki takie jak jQuery wiedziały jednak o tych ograniczeniach i omijały je za kulisami. Myślę więc, że moja odpowiedź jest ważna.
Crono
27

1. Kompatybilność wsteczna

JavaScript jest implementacją ECMAScript . Większość tych funkcji została wprowadzona w ECMAScript 5 (ES5), jednak wiele starszych przeglądarek, które nadal mają wystarczająco duży udział w rynku, nie obsługuje tych funkcji (patrz tabela kompatybilności ECMAScript 5 ), z których najbardziej godne uwagi jest IE8.

Zasadniczo biblioteki powrócą do implementacji natywnej, jeśli istnieje, w przeciwnym razie użyj własnego wypełniania, na przykład spójrzmy na implementację 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;
}

Poniższe wiersze sprawdzają, czy forEachmetoda istnieje na obiekcie i czy jest to wersja AngularJS, czy nie. Jeśli nie, używa już określonej funkcji (wersja natywna):

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

2. Wygoda

W natywnym JavaScript Array.prototype.forEachjest metodą wyłączną dla instancji Array, jednak większość z nich Objectjest również iterowalna.

Z tego powodu wielu twórców bibliotek uczyniło swoje funkcje polimorficznymi (zdolnymi do przyjmowania wielu typów jako danych wejściowych). Weźmy powyżej kod AngularJS i zobaczmy, jakie dane wejściowe akceptuje:

Funkcje :

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

Tablice (z natywną obsługą forEach):

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

Obiekty podobne do tablicy, w tym Array (bez natywnej obsługi forEach), String, HTMLElement, Object z prawidłową właściwością length:

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

Obiekty:

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

Wniosek

Jak widać, AngularJS będzie iterował większość obiektów JavaScript, chociaż działa w taki sam sposób, jak natywna funkcja, akceptuje znacznie więcej różnych typów danych wejściowych, a zatem jest ważnym dodatkiem do biblioteki, a także sposobem na wprowadzenie funkcji ES5 do starszych przeglądarek.

George Reith
źródło
2
Możesz zaktualizować swój link, aby wskazywał na konkretne zatwierdzenie (np. Angular.js L203-257 ) do przyszłego odniesienia po masterzmianie.
Whymarrh