Для перевантаження аргументів у Javascript є кілька аспектів:
Змінні аргументи - Ви можете передавати різні набори аргументів (як за типом, так і за кількістю), і функція буде вести себе таким чином, що відповідає аргументам, переданим їй.
Аргументи за замовчуванням - Ви можете визначити значення аргументу за замовчуванням, якщо воно не передано.
Іменовані аргументи - Порядок аргументів стає неактуальним, і ви просто назвете, які аргументи ви хочете передати функції.
Нижче наведено розділ щодо кожної з цих категорій обробки аргументів.
Змінні аргументи
Оскільки javascript не має перевірки типів аргументів або необхідної кількості аргументів, ви можете просто виконати одну реалізацію, myFunc()яка може адаптувати до того, які аргументи були передані йому, перевіривши тип, наявність чи кількість аргументів.
jQuery робить це постійно. Ви можете зробити деякі аргументи необов’язковими або ви можете розгалужувати свою функцію залежно від того, які аргументи передаються до неї.
Виконуючи такі типи перевантажень, ви можете використовувати декілька різних технік:
- Ви можете перевірити наявність будь-якого заданого аргументу, перевіривши, чи є оголошене значення імені аргументу
undefined.
- Ви можете перевірити загальну кількість або аргументи за допомогою
arguments.length.
- Ви можете перевірити тип будь-якого заданого аргументу.
- Для змінної кількості аргументів ви можете використовувати
argumentsпсевдомасив для доступу до будь-якого заданого аргументу arguments[i].
Ось кілька прикладів:
Давайте розглянемо obj.data()метод jQuery . Він підтримує чотири різні форми використання:
obj.data("key");
obj.data("key", value);
obj.data();
obj.data(object);
Кожен з них викликає іншу поведінку, і, не використовуючи цю динамічну форму перевантаження, знадобиться чотири окремих функції.
Ось як можна розрізнити всі ці параметри англійською мовою, і тоді я з’єднаю їх у коді:
// get the data element associated with a particular key value
obj.data("key");
Якщо перший аргумент, який передається .data(), це рядок, а другий аргумент - undefined, то абонент повинен використовувати цю форму.
// set the value associated with a particular key
obj.data("key", value);
Якщо другий аргумент не визначений, то встановіть значення конкретного ключа.
// get all keys/values
obj.data();
Якщо жодних аргументів не передано, поверніть усі ключі / значення у поверненому об'єкті.
// set all keys/values from the passed in object
obj.data(object);
Якщо тип першого аргументу - звичайний об'єкт, то встановіть усі ключі / значення з цього об’єкта.
Ось як можна поєднати все це в одному наборі логіки 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
}
},
Ключ до цієї методики полягає в тому, щоб переконатися, що всі форми аргументів, які ви хочете прийняти, є однозначно ідентифікованими, і ніколи не буде плутанини щодо того, яку форму використовує абонент. Це, як правило, вимагає впорядкування аргументів і переконання в достатній унікальності у типі та положенні аргументів, які ви завжди можете сказати, яка форма використовується.
Наприклад, якщо у вас є функція, яка бере три рядкові аргументи:
obj.query("firstArg", "secondArg", "thirdArg");
Ви можете легко зробити третій аргумент необов’язковим, і ви можете легко визначити цю умову, але ви не можете зробити лише другий аргумент необов'язковим, оскільки ви не можете сказати, який із цих абонентів означає пройти, оскільки немає способу визначити, чи є другий аргумент мається на увазі як другий аргумент або другий аргумент опущений, тому те, що знаходиться в місці другого аргументу, є насправді третім аргументом:
obj.query("firstArg", "secondArg");
obj.query("firstArg", "thirdArg");
Оскільки всі три аргументи одного типу, ви не можете вказати різницю між різними аргументами, щоб ви не знали, що призначений абонент. У цьому стилі виклику лише третій аргумент може бути необов'язковим. Якщо ви хочете опустити другий аргумент, він повинен бути переданий як 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, де аргумент може бути відсутнім або будь-який із трьох різних типів, який дає чотири різні перевантаження:
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's $.ajax()приймає форму використання, де ви просто передаєте йому єдиний параметр, який є звичайним об'єктом Javascript зі властивостями та значеннями. Які властивості ви передаєте йому, визначайте, які аргументи / параметри передаються до виклику ajax. Деякі можуть знадобитися, багато - необов’язково. Оскільки вони є властивостями об’єкта, конкретного порядку немає. Насправді на цьому об’єкті можна передати більше 30 різних властивостей, потрібна лише одна (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 можна використовувати руйнування для створення властивостей / значень за замовчуванням для вищепереданого об'єкта. Про це детальніше йдеться в цій довідковій статті .
Ось один приклад із цієї статті:
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 .