[javascript] JavaScript에서 함수 호출에 명명 된 매개 변수를 제공하는 방법이 있습니까?

C #의 명명 된 매개 변수 기능은 경우에 따라 매우 유용합니다.

calculateBMI(70, height: 175);

JavaScript로 이것을 원한다면 무엇을 사용할 수 있습니까?


내가 원하지 않는 것은 이것입니다.

myFunction({ param1: 70, param2: 175 });

function myFunction(params){
  // Check if params is an object
  // Check if the parameters I need are non-null
  // Blah blah
}

내가 이미 사용한 접근법. 다른 방법이 있습니까?

라이브러리를 사용 하여이 작업을 수행 할 수 있습니다.



답변

ES2015 이상

ES2015에서는 매개 변수 파괴 를 사용하여 명명 된 매개 변수를 시뮬레이션 할 수 있습니다. 호출자가 객체를 전달해야하지만 기본 매개 변수를 사용하는 경우 함수 내부의 모든 검사를 피할 수 있습니다.

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

원하는 것에 가깝게 접근 할 수있는 방법이 있지만 , 구현에 어느 정도 의존하는 Function.prototype.toString [ES5] 출력을 기반으로 하므로 브라우저 간 호환되지 않을 수 있습니다.

아이디어는 객체의 속성을 해당 매개 변수와 연결할 수 있도록 함수의 문자열 표현에서 매개 변수 이름을 구문 분석하는 것입니다.

함수 호출은 다음과 같습니다

func(a, b, {someArg: ..., someOtherArg: ...});

위치 인수는 어디 a이며 b마지막 인수는 인수가 명명 된 객체입니다.

예를 들면 다음과 같습니다.

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

당신은 다음과 같이 사용할 것입니다 :

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 

데모

이 접근 방식 에는 몇 가지 단점 이 있습니다 (경고되었습니다!).

  • 마지막 인수가 객체 인 경우 “명명 된 인수 객체”로 취급됩니다.
  • 함수에서 정의한만큼 많은 인수를 얻을 수 있지만 그 중 일부에는 값이있을 수 있습니다 (값 undefined이없는 것과는 다름). 즉, arguments.length몇 개의 인수가 전달되었는지 테스트 할 수 없습니다 .

랩퍼를 작성하는 함수 대신 함수와 다양한 값을 인수로 허용하는 함수를 가질 수도 있습니다.

call(func, a, b, {posArg: ... });

또는 다음과 같이 할 수 Function.prototype있도록 확장하십시오 .

foo.execute(a, b, {posArg: ...});


답변

아니요 -객체 접근 방식은 이에 대한 JavaScript의 답변입니다. 함수가 별도의 매개 변수가 아닌 객체를 기대하는 경우에는 아무런 문제가 없습니다.


답변

이 문제는 한동안 내 애완 동물이었던 것입니다. 나는 내 벨트 아래에 많은 언어를 가진 노련한 프로그래머입니다. 내가 가장 좋아하는 언어 중 하나는 Python입니다. 파이썬은 속임수없이 명명 된 매개 변수를 지원합니다 …. 파이썬을 사용하기 시작한 이래 (모든 시간 전에) 모든 것이 쉬워졌습니다. 모든 언어가 명명 된 매개 변수를 지원해야한다고 생각하지만, 그렇지 않습니다.

많은 사람들이 매개 변수 이름을 지정하기 위해 “Pass an object”트릭을 사용한다고 말합니다.

/**
 * My Function
 *
 * @param {Object} arg1 Named arguments
 */
function myFunc(arg1) { }

myFunc({ param1 : 70, param2 : 175});

그리고 대부분의 IDE에 관해서는 많은 개발자들이 IDE 내에서 유형 / 인수 힌트에 의존합니다. 나는 개인적으로 PHP Storm을 사용합니다 (PyCharm for Python 및 AppCode for Objective C와 같은 다른 JetBrains IDE와 함께)

“Pass an object”트릭을 사용할 때 가장 큰 문제는 함수를 호출 할 때 IDE가 단일 유형 힌트를 제공한다는 것입니다. arg1 객체?

arg1에 어떤 매개 변수가 들어 가야할지 모르겠습니다.

그래서 … “Pass an object”트릭이 저에게는 효과가 없습니다 … 실제로 함수가 어떤 매개 변수를 기대하는지 알기 전에 각 함수의 docblock을 살펴 봐야하는 두통이 더 많이 생깁니다 …. 물론입니다. 기존 코드를 유지할 때 새 코드를 작성하는 것은 끔찍합니다.

글쎄, 이것은 내가 사용하는 기술입니다 …. 이제는 몇 가지 문제가있을 수 있으며 일부 개발자는 내가 잘못하고 있다고 말할 수 있습니다. 나는 항상 작업을 수행하는 더 나은 방법을 기꺼이 생각합니다 … 따라서이 기술에 문제가 있으면 의견을 환영합니다.

/**
 * My Function
 *
 * @param {string} arg1 Argument 1
 * @param {string} arg2 Argument 2
 */
function myFunc(arg1, arg2) { }

var arg1, arg2;
myFunc(arg1='Param1', arg2='Param2');

이런 식으로, 나는 두 세계의 장점을 모두 가지고 있습니다 … IDE에서 모든 적절한 인수 힌트를 제공하므로 새로운 코드를 작성하기 쉽습니다 … 나중에 코드를 유지하면서 한 눈에 볼 수 있습니다. 함수에 전달 된 값뿐만 아니라 인수의 이름도 전달됩니다. 내가 보는 유일한 오버 헤드는 전역 네임 스페이스를 오염시키지 않도록 인수 이름을 로컬 변수로 선언하는 것입니다. 물론 약간의 추가 타이핑이지만 새 코드를 작성하거나 기존 코드를 유지하면서 docblock을 찾는 데 걸리는 시간과 비교하면 사소한 것입니다.

이제 새 코드를 만들 때 모든 매개 변수와 유형이 있습니다.


답변

단순히 호출하는 것이 아니라 각 매개 변수가 무엇인지 명확하게하려면

someFunction(70, 115);

왜 다음을하지 않습니까

var width = 70, height = 115;
someFunction(width, height);

추가 코드 줄이지 만 가독성이 좋습니다.


답변

다른 방법은 적절한 객체의 속성을 사용하는 것입니다.

function plus(a,b) { return a+b; };

Plus = { a: function(x) { return { b: function(y) { return plus(x,y) }}},
         b: function(y) { return { a: function(x) { return plus(x,y) }}}};

sum = Plus.a(3).b(5);

물론이 예제에서는 다소 의미가 없습니다. 그러나 함수가 다음과 같은 경우

do_something(some_connection_handle, some_context_parameter, some_value)

더 유용 할 수 있습니다. 또한 “매개 변수화”아이디어와 결합하여 일반적인 방식으로 기존 함수에서 이러한 개체를 생성 할 수 있습니다. 즉, 각 매개 변수에 대해 부분 평가 버전의 함수로 평가할 수있는 멤버를 만듭니다.

이 아이디어는 물론 Schönfinkeling aka Currying과 관련이 있습니다.


답변

다른 방법이 있습니다. 객체를 참조로 전달하는 경우 해당 객체의 속성이 함수의 로컬 범위에 나타납니다. 나는 이것이 Safari (다른 브라우저를 확인하지 않은)에서 작동한다는 것을 알고 있으며이 기능에 이름이 있는지 모르겠지만 아래 예제는 그 사용법을 보여줍니다.

실제로 나는 이것이 이미 사용중인 기술 이외의 기능적 가치를 제공한다고 생각하지 않지만 의미 적으로 조금 더 깨끗합니다. 그리고 여전히 객체 참조 또는 객체 리터럴을 전달해야합니다.

function sum({ a:a, b:b}) {
    console.log(a+'+'+b);
    if(a==undefined) a=0;
    if(b==undefined) b=0;
    return (a+b);
}

// will work (returns 9 and 3 respectively)
console.log(sum({a:4,b:5}));
console.log(sum({a:3}));

// will not work (returns 0)
console.log(sum(4,5));
console.log(sum(4));


답변

Node-6.4.0 (process.versions.v8 = ‘5.0.71.60’) 및 Node Chakracore-v7.0.0-pre8 및 Chrome-52 (V8 = 5.2.361.49)를 시도하면 명명 된 매개 변수가 거의 임을 알았습니다. 구현되었지만 그 순서가 여전히 우선합니다. ECMA 표준이 말하는 것을 찾을 수 없습니다.

>function f(a=1, b=2){ console.log(`a=${a} + b=${b} = ${a+b}`) }

> f()
a=1 + b=2 = 3
> f(a=5)
a=5 + b=2 = 7
> f(a=7, b=10)
a=7 + b=10 = 17

그러나 주문이 필요합니다! 표준 행동입니까?

> f(b=10)
a=10 + b=2 = 12