フレームワーク/ライブラリはすでにネイティブに存在しているにもかかわらず、独自のヘルパーを持っているのはなぜですか。
jQuery と AngularJS を取り上げます。これらには独自のeach
イテレータ関数があります:
しかし、_Array.prototype.forEach
_があります。
同様に、
しかし、バニラJavaScriptにはJSON.parse()
関数があります。
これらのライブラリが作成されたとき、一部の主要なブラウザはそれらの機能をサポートしていませんでした。いったん作成して使用すると、これらの機能を多くのアプリケーションを壊さずにこれらのライブラリから削除することはできません。
(この場合、「メジャーブラウザー」とは、まだ大きな市場シェアを持っているブラウザーを意味します。これには、多数のユーザーが必ずしも最新バージョンにアップグレードする必要がないInternet Explorerなどの古いバージョンのブラウザーが含まれます。)
ブラウザごとに実装や機能が異なりますがJavaScriptエンジンに組み込まれているためです。同じ「Vanilla-JS」コードは、2つの異なるブラウザー、または同じブラウザーの2つの異なるバージョンで異なる方法で実行できます。
一般的なJSライブラリによって提供される抽象化レイヤーは、これを回避する方法です。舞台裏では、さまざまなブラウザーの容量と制限に対処し、それらに加えて、統一された使いやすいAPIを提供します。これにより、DOMオブジェクトの取得やJSONデータのフェッチなどの一般的な操作を、一貫性があり、効率的でブラウザーに依存しないものにすることができます。
これにより、ブラウザーXまたはYで動作するようにコードを記述する方法よりも、コードが実行する必要のあることに集中できる開発者にとって、生活がはるかに容易になります。
JavaScriptは ECMAScript の実装です。これらの関数のほとんどはECMAScript 5(ES5)で導入されましたが、依然として市場で十分なシェアを持っている多くの古いブラウザーはこれらの関数をサポートしていません( ECMAScript 5互換性テーブル を参照)。これらはIE8です。
一般に、ライブラリは存在する場合はネイティブの実装に戻ります。それ以外の場合は独自のポリフィルを使用します。たとえば、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);
}
ネイティブJavaScript Array.prototype.forEach
はArray
のインスタンス専用のメソッドですが、ほとんどのObject
も反復可能です。
このため、多くのライブラリ作成者は関数を作成します polymorphic (複数のタイプを入力として受け入れることができます)。上記の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);
}
}
Arrays(ネイティブforEachサポートあり):
} else if (obj.forEach && obj.forEach !== forEach) {
obj.forEach(iterator, context);
Array-like objects配列を含む(ネイティブのforEachサポートなし)、String、HTMLElement、有効な長さプロパティを持つオブジェクト:
} 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関数をもたらす方法です。レガシーブラウザに。