ES2015 i nowsze
W ES2015 destrukcji parametrów można użyć do symulacji nazwanych parametrów. Wymagałoby to od obiektu wywołującego przekazania obiektu, ale można uniknąć wszystkich kontroli wewnątrz funkcji, jeśli zostaną użyte również parametry domyślne:
myFunction({ param1 : 70, param2 : 175});
function myFunction({param1, param2}={}){
// ...function body...
}
// Or with defaults,
function myFunc({
name = 'Default user',
age = 'N/A'
}={}) {
// ...function body...
}
ES5
Istnieje sposób, aby zbliżyć się do tego, co chcesz, ale opiera się on na Function.prototype.toString
wynikach [ES5] , który jest w pewnym stopniu zależny od implementacji, więc może nie być kompatybilny z różnymi przeglądarkami.
Chodzi o to, aby parsować nazwy parametrów z reprezentacji ciągu funkcji, aby można było powiązać właściwości obiektu z odpowiednim parametrem.
Wywołanie funkcji mogłoby wtedy wyglądać
func(a, b, {someArg: ..., someOtherArg: ...});
gdzie a
i b
są argumentami pozycyjnymi, a ostatni argument jest obiektem o nazwanych argumentach.
Na przykład:
var parameterfy = (function() {
var pattern = /function[^(]*\(([^)]*)\)/;
return function(func) {
// fails horribly for parameterless functions ;)
var args = func.toString().match(pattern)[1].split(/,\s*/);
return function() {
var named_params = arguments[arguments.length - 1];
if (typeof named_params === 'object') {
var params = [].slice.call(arguments, 0, -1);
if (params.length < args.length) {
for (var i = params.length, l = args.length; i < l; i++) {
params.push(named_params[args[i]]);
}
return func.apply(this, params);
}
}
return func.apply(null, arguments);
};
};
}());
Które byś użył jako:
var foo = parameterfy(function(a, b, c) {
console.log('a is ' + a, ' | b is ' + b, ' | c is ' + c);
});
foo(1, 2, 3); // a is 1 | b is 2 | c is 3
foo(1, {b:2, c:3}); // a is 1 | b is 2 | c is 3
foo(1, {c:3}); // a is 1 | b is undefined | c is 3
foo({a: 1, c:3}); // a is 1 | b is undefined | c is 3
PRÓBNY
Istnieje kilka wad tego podejścia (zostałeś ostrzeżony!):
- Jeśli ostatnim argumentem jest obiekt, jest on traktowany jako „nazwany obiekt argumentu”
- Zawsze dostaniesz tyle argumentów, ile zdefiniowałeś w funkcji, ale niektóre z nich mogą mieć wartość
undefined
(która różni się od braku żadnej wartości). Oznacza to, że nie można użyć arguments.length
do sprawdzenia, ile argumentów zostało przekazanych.
Zamiast mieć funkcję tworzącą opakowanie, możesz również mieć funkcję, która akceptuje funkcję i różne wartości jako argumenty, takie jak
call(func, a, b, {posArg: ... });
lub nawet rozszerzyć Function.prototype
, abyś mógł:
foo.execute(a, b, {posArg: ...});