JavaScriptの引数のオーバーロードには複数の側面があります。
可変引数 -異なる引数のセット(タイプと数量の両方)を渡すことができ、関数は渡された引数と一致するように動作します。
デフォルト引数 -渡されない場合、引数のデフォルト値を定義できます。
名前付き引数 -引数の順序は無関係になり、関数に渡す引数に名前を付けるだけです。
以下は、これらの引数処理の各カテゴリーに関するセクションです。
可変引数
JavaScriptには引数の型チェックや必要な数の引数がないため、引数myFunc()の型、存在、または数量をチェックすることで、渡された引数に適応できる実装を1つだけ持つことができます。
jQueryはこれを常に行います。一部の引数をオプションにするか、渡される引数に応じて関数内で分岐できます。
これらのタイプのオーバーロードを実装するには、いくつかの異なる手法を使用できます。
- 宣言された引数名の値がであるかどうかを確認することにより、特定の引数の存在を確認できます
undefined。
- 合計数量または引数をで確認できます
arguments.length。
- 任意の引数のタイプを確認できます。
- 引数の数が可変の場合、
arguments疑似配列を使用して、で任意の引数にアクセスできますarguments[i]。
ここではいくつかの例を示します。
jQueryのobj.data()メソッドを見てみましょう。4つの異なる使用方法をサポートしています。
obj.data("key");
obj.data("key", value);
obj.data();
obj.data(object);
それぞれが異なる動作をトリガーし、この動的なオーバーロードの形式を使用しないと、4つの個別の関数が必要になります。
これらのオプションを英語で識別できる方法を以下に示します。コードでそれらをすべて組み合わせます。
// get the data element associated with a particular key value
obj.data("key");
に渡される最初の引数が.data()文字列で、2番目の引数がのundefined場合、呼び出し元はこの形式を使用している必要があります。
// set the value associated with a particular key
obj.data("key", value);
2番目の引数が未定義でない場合は、特定のキーの値を設定します。
// get all keys/values
obj.data();
引数が渡されない場合は、返されたオブジェクトのすべてのキー/値を返します。
// set all keys/values from the passed in object
obj.data(object);
最初の引数のタイプがプレーンオブジェクトの場合、そのオブジェクトからすべてのキー/値を設定します。
これらすべてを1つのJavaScriptロジックのセットに組み合わせる方法を次に示します。
// method declaration for .data()
data: function(key, value) {
if (arguments.length === 0) {
// .data()
// no args passed, return all keys/values in an object
} else if (typeof key === "string") {
// first arg is a string, look at type of second arg
if (typeof value !== "undefined") {
// .data("key", value)
// set the value for a particular key
} else {
// .data("key")
// retrieve a value for a key
}
} else if (typeof key === "object") {
// .data(object)
// set all key/value pairs from this object
} else {
// unsupported arguments passed
}
},
この手法の鍵は、受け入れたい引数のすべての形式が一意に識別可能であり、呼び出し元がどの形式を使用しているかについて混乱がないことを確認することです。これには、通常、引数を適切に順序付けし、引数のタイプと位置に十分な一意性があり、どのフォームが使用されているかを常に確認できるようにする必要があります。
たとえば、3つの文字列引数を取る関数があるとします。
obj.query("firstArg", "secondArg", "thirdArg");
3番目の引数を簡単にオプションにしてその条件を簡単に検出できますが、2番目の引数だけをオプションにすることはできません。引数は2番目の引数であることを意味するか、2番目の引数が省略されたため、2番目の引数のスポットには実際には3番目の引数があります。
obj.query("firstArg", "secondArg");
obj.query("firstArg", "thirdArg");
3つの引数はすべて同じ型であるため、異なる引数の違いを見分けることができないため、呼び出し元の意図がわかりません。この呼び出しスタイルでは、3番目の引数のみをオプションにすることができます。2番目の引数を省略したい場合は、null代わりに(またはその他の検出可能な値)として渡す必要があり、コードはそれを検出します。
obj.query("firstArg", null, "thirdArg");
以下は、オプションの引数のjQueryの例です。両方の引数はオプションであり、渡されない場合はデフォルト値を取ります。
clone: function( dataAndEvents, deepDataAndEvents ) {
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
return this.map( function () {
return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
});
},
以下は、引数が欠落している可能性があるjQueryの例、または4つの異なるオーバーロードを提供する3つの異なるタイプのいずれかです。
html: function( value ) {
if ( value === undefined ) {
return this[0] && this[0].nodeType === 1 ?
this[0].innerHTML.replace(rinlinejQuery, "") :
null;
// See if we can take a shortcut and just use innerHTML
} else if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
(jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&
!wrapMap[ (rtagName.exec( value ) || ["", ""])[1].toLowerCase() ] ) {
value = value.replace(rxhtmlTag, "<$1></$2>");
try {
for ( var i = 0, l = this.length; i < l; i++ ) {
// Remove element nodes and prevent memory leaks
if ( this[i].nodeType === 1 ) {
jQuery.cleanData( this[i].getElementsByTagName("*") );
this[i].innerHTML = value;
}
}
// If using innerHTML throws an exception, use the fallback method
} catch(e) {
this.empty().append( value );
}
} else if ( jQuery.isFunction( value ) ) {
this.each(function(i){
var self = jQuery( this );
self.html( value.call(this, i, self.html()) );
});
} else {
this.empty().append( value );
}
return this;
},
名前付き引数
他の言語(Pythonなど)では、一部の引数のみを渡し、渡された順序とは無関係に引数を作成する手段として、名前付き引数を渡すことができます。JavaScriptは、名前付き引数の機能を直接サポートしていません。その場所で一般的に使用される設計パターンは、プロパティ/値のマップを渡すことです。これは、プロパティと値を持つオブジェクトを渡すことで実行できます。ES6以降では、実際にMapオブジェクト自体を渡すことができます。
ES5の簡単な例を次に示します。
jQuery $.ajax()は、プロパティと値を持つ通常のJavaScriptオブジェクトである単一のパラメーターを渡すだけの使用法を受け入れます。渡すプロパティによって、どの引数/オプションがajax呼び出しに渡されるかが決まります。一部は必須で、多くはオプションです。それらはオブジェクトのプロパティであるため、特定の順序はありません。実際、そのオブジェクトに渡すことができる30を超える異なるプロパティがあり、1つ(URL)のみが必要です。
次に例を示します。
$.ajax({url: "http://www.example.com/somepath", data: myArgs, dataType: "json"}).then(function(result) {
// process result here
});
$.ajax()実装の内部では、着信オブジェクトで渡されたプロパティを調べ、名前付き引数として使用できます。これはfor (prop in obj)、すべてのプロパティを配列に入れて、その配列をObject.keys(obj)反復することによって、またはそのいずれかによって行うことができます。
この手法は、引数が多数ある場合や、多くの引数がオプションである場合に、JavaScriptで非常によく使用されます。注:これは実装する関数に負担をかけ、最小限の有効な引数のセットが存在することを確認し、不十分な引数が渡された場合に不足しているものを呼び出し側にデバッグフィードバックを提供します(おそらく、有用なエラーメッセージで例外をスローすることによって)。 。
ES6環境では、構造化を使用して、上記で渡されたオブジェクトのデフォルトのプロパティ/値を作成することができます。これについては、このリファレンス記事で詳しく説明しています。
その記事の1つの例を次に示します。
function selectEntries({ start=0, end=-1, step=1 } = {}) {
···
};
これにより、のデフォルトのプロパティと値start、endおよび関数にstep渡されるオブジェクトのプロパティが作成されますselectEntries()。
関数の引数のデフォルト値
ES6では、JavaScriptが引数のデフォルト値の組み込み言語サポートを追加します。
例えば:
function multiply(a, b = 1) {
return a*b;
}
multiply(5); // 5
これをMDNで使用する方法の詳細。