为什么JavaScript框架/库具有纯JavaScript中已经存在的功能?


60

我想知道为什么框架/库虽然本身已经存在,但是却有自己的帮助器。

让我们以jQueryAngularJS为例。它们具有自己的each迭代器功能:

但是我们有Array.prototype.forEach

同样,

但是我们JSON.parse()在原始JavaScript中具有该功能。


75
作为记得Web开发的糟糕过去的人,这个问题让我哭了。
josh3736 2014年

3
@ josh3736至少您仍然不需要支持IE6('幸运的是,仅以“使其正常运行,看起来像胡扯”的方式)
Izkata 2014年

12
jQuery.each并且Array.prototype.forEach不是等效的。
zzzzBov 2014年

3
您应该问自己:现在在vanillaJS中发现了多少功能,这些功能源自jQ之类的工具包?答案是:很多。这就引出了一个问题:我们为什么仍在使用它们?为什么要包括jQuery $.each而不使用本机(且速度更快)Array.prototype.forEach
Elias Van Ootegem 2014年

1
@ josh3736没关系,兄弟... i.stack.imgur.com/HJs4V.jpg
Crono

Answers:


93

因为在编写这些库时,某些主要的浏览器不支持这些功能。一旦编写和使用这些功能,就无法从这些库中删除这些功能,而不会破坏许多应用程序。

(在这种情况下,“主要浏览器”是指仍具有较大市场份额的浏览器,其中包括较旧版本的浏览器,例如Internet Explorer,其中大量用户不一定升级到最新版本。)


44
$('marquee')。each(function(){$(this).append($('<bgsound />',{src:“ good-answer.mp3”})))});
皮埃尔·阿洛德

36
@dirkk不是最近的浏览器不支持它。并不是每个人都有幸拥有使用最新浏览器的受众群体。
乔治·瑞斯

14
Array.prototype.forEach仅在数组上迭代-两个库迭代器函数都可以在数组或对象上迭代。
JoeG 2014年

3
这些功能在那里支持旧的浏览器,并支持调用该库的旧代码,并且程序员不想重写。即使您放弃了对IE 6的支持,当您确实需要支持IE的较早版本时,您可能仍在使用一些JavaScript。
Michael Shopsin 2014年

6
许多此类函数(例如jQuery.parseJSON())仅检查浏览器是否支持它,然后将其自身设置为浏览器方法,并且仅在不兼容的浏览器上使用替代方法!
2014年

35

因为不同的浏览器在其JavaScript引擎中具有不同的实现和功能。相同的“ vanilla-JS”代码可以在两个不同的浏览器上甚至在同一浏览器的两个不同版本上以不同的方式运行。

流行的JS库提供的抽象层是解决此问题的一种方法。在幕后,它可以解决不同浏览器的功能和限制,并在这些功能和限制的基础上提供统一,易于使用的API。反过来,这允许诸如获取DOM对象或获取JSON数据之类的常见操作一致,高效且与浏览器无关。

对于现在可以专注于代码应该做什么而不是如何编写与X或Y浏览器一起使用的开发人员来说,这使工作变得更加轻松。


2
对“核心JS”的行为进行了详细说明,并在所有浏览器中进行了测试。
Domenic 2014年

2
除了@Domenic语法外,不同浏览器的javascript实现也有所不同。您只能在少数几个浏览器中找到某些属性,方法,事件和功能,有时甚至只有一个。
克罗诺2014年

1
是的,浏览器具有非标准功能。这与本问题中讨论的标准功能无关。
Domenic 2014年

8
@Domenic如果用“问题中讨论的标准功能”来表示Array.prototype.forEachJSON.parse功能,那么在Google上进行快速搜索将显示您错了。JSONIE7不支持该对象,并且forEach在某些Opera版本中未定义该对象。但是,像jQuery这样的库确实了解这些限制,并在幕后进行了处理。所以我认为我的回答确实成立。
Crono 2014年

27

1.向后兼容

JavaScript是ECMAScript的实现。这些功能大多数是在ECMAScript 5(ES5)中引入的,但是,许多仍然占有相当大市场份额的较旧的浏览器不支持这些功能(请参阅ECMAScript 5兼容性表),其中最著名的是IE8。

通常,如果存在库,则库将还原为本机实现,否则使用其自己的polyfill,例如,让我们看一下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;
}

以下几行检查该forEach方法是否存在于对象上以及它是否为AngularJS版本。如果不是,它将使用已经指定的功能(本机版本):

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

2.便利

在本机JavaScript中,Array.prototype.forEach是的实例专有的方法Array,但是大多数方法Object也是可迭代的。

因此,许多库创建者使它们的函数成为多态的(能够接受多种类型作为输入)。让我们看一下上面的AngularJS代码,看看它接受什么输入:

功能

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

数组(具有原生forEach支持):

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

类似于数组的对象,包括数组(不支持本地forEach),字符串,HTMLElement和具有有效length属性的对象:

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

结论

如您所见,AngularJS会迭代大多数JavaScript对象,尽管它的工作方式与本机函数相同,但它接受的输入类型要多得多,因此是对库的有效补充,也是带来ES5函数的一种方式到旧版浏览器。


2
您可能希望更新链接以指向特定的提交(例如,angular.js L203-257),以供将来master更改时参考。
Whymarrh 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.