programing

JavaScript에서 함수 호출에 명명된 파라미터를 제공하는 방법이 있습니까?

goodsources 2022. 10. 1. 15:21
반응형

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

원하는 것에 근접하는 방법은 있지만,[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의 답변입니다.함수가 별도의 매개 변수가 아닌 개체를 예상하는 경우 이 문제는 없습니다.

많은 사람들이 파라미터 이름을 붙이기 위해 "물체 전달" 기술을 사용하라고 합니다.

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

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

이 방법은 매우 효과적입니다.단, 대부분의 IDE에 관해서는 많은 개발자가 IDE 내의 유형/논쟁 힌트에 의존하고 있습니다.저는 개인적으로 PHP Storm (파이썬용 PyCharm, 오브젝티브 C용 AppCode와 같은 다른 JetBrains IDE와 함께)을 사용하고 있습니다.

"Pass an object" 트릭을 사용할 때 가장 큰 문제는 함수를 호출할 때 IDE가 단일 유형의 힌트를 제공한다는 것입니다.arg1 오브젝트에 어떤 파라미터와 타입이 들어가는지 어떻게 알 수 있을까요?

arg1에 어떤 파라미터가 들어가야 하는지 모르겠다.

그래서... '물건 넘기기'는 나한테는 통하지 않아실제로 각 함수의 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가 적절한 주장 힌트를 주기 때문에 쓰기 쉽습니다.그리고 나중에 코드를 유지하면서 함수에 전달된 값뿐만 아니라 인수의 이름까지 한눈에 볼 수 있습니다.오버헤드는 인수명을 로컬 변수로 선언하여 글로벌네임스페이스를 오염시키지 않도록 하는 것뿐입니다.물론 약간의 추가 입력이지만 새 코드를 작성하거나 기존 코드를 유지 관리하는 동안 문서 블록을 검색하는 데 걸리는 시간에 비하면 매우 간단합니다.

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

단순히 콜하는 것이 아니라 각 파라미터가 무엇인지 명확히 하고 싶은 경우

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)

그게 더 유용할 수도 있어또한 "파라미터피" 아이디어와 결합하여 일반적인 방법으로 기존 함수에서 이러한 개체를 만들 수도 있습니다.즉, 각 파라미터에 대해 함수의 일부 평가 버전으로 평가할 수 있는 멤버를 만듭니다.

이 아이디어는 물론 Currying이라고 불리는 Schönfinkeling과 관련이 있다.

호출 함수f명명된 매개 변수가 개체로 전달됨

o = {height: 1, width: 5, ...}

기본적으로 그 구성을f(...g(o))spread 구문을 사용하고 있습니다.g는 오브젝트 값과 파라미터 위치를 연결하는 "바인딩" 맵입니다.

바인딩 맵은 정확히 누락된 구성요소이며, 키의 배열로 나타낼 수 있습니다.

// map 'height' to the first and 'width' to the second param
binding = ['height', 'width']

// take binding and arg object and return aray of args
withNamed = (bnd, o) => bnd.map(param => o[param])

// call f with named args via binding
f(...withNamed(binding, {hight: 1, width: 5}))

가지 분리된 구성요소, 즉 함수, 명명된 인수를 가진 개체 및 바인딩에 주의하십시오.이 디커플링은 이 구조를 사용하는 데 많은 유연성을 허용하며, 여기서 바인딩은 함수의 정의에서 임의로 커스터마이즈되고 함수 호출 시 임의로 확장될 수 있습니다.

예를 들어 다음과 같이 생략할 수 있습니다.height그리고.width~하듯이h그리고.w함수의 정의를 사용하여 보다 짧고 깔끔하게 할 수 있습니다.단, 알기 쉽게 풀네임으로 호출할 수도 있습니다.

// use short params
f = (h, w) => ...

// modify f to be called with named args
ff = o => f(...withNamed(['height', 'width'], o))

// now call with real more descriptive names
ff({height: 1, width: 5})

이러한 유연성은 함수 프로그래밍에서도 더욱 유용하며, 함수들은 원래 파라미터 이름이 손실된 상태에서 임의로 변환될 수 있습니다.

다른 방법이 있어요.참조로 개체를 전달하는 경우 해당 개체의 속성이 함수의 로컬 범위에 나타납니다.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));

Python에서 오면서 나는 신경이 쓰였다.positional 객체와 키워드 객체를 모두 수용하는 노드용 간단한 wrapper/Proxy를 작성했습니다.

https://github.com/vinces1979/node-def/blob/master/README.md

이것은 분명히 의사 코드이지만, 동작할 것이라고 생각합니다(Typescript로 동작하는 것을 알고 있습니다.JavaScript용으로 채택하고 있습니다).

// Target Function
const myFunc = (a=1,b=2,c=3) => {a+b+c}

// Goal usage:
myFunc(a=5, b=6) // 14
myFunc(c=0) // 3

// set your defaults
const myFuncDefaults = {a:1, b:2, c:3};

// override them with passed params
const myFuncParams = (params) => { return Object.assign(myFuncDefaults, params)}


// use the overloaded dict as the input
const myFunc2 = (params) => {
  let {a, b, c} = myFuncParams(params);
  return myFunc(a, b, c)
}

// Usage:
myFunc({a:5, b:6}) // 14
myFunc({c:0}) // 3

// Written more succinctly:
const myFunc = (params) => {
  let {a,b,c} = Object.assign({a:1, b:2, c:3}, params)
  return a + b + c
}

FWIW 타입 스크립트에서는 다음과 같은 힌트를 얻을 수 있습니다.

interface IParams {
  a: number;
  b: number;
  c: number;
}

const myFunc = (params: Partial<IParams>): number => {
  const default: IParams = {a:1, b:2, c:3};
  let {a, b, c} = Object.assign(default, params)
  return a + b + c
}

NB. 2016년 제 답변은 댓글에 있는 것처럼 정확하지 않고 오해의 소지가 있습니다.

Node-6.4.0 (프로세스).버전.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

, 뭐, 그런 셈이죠.저는 두 가지 해결책을 찾았습니다.하나만 설명할게요.

이 솔루션에서는 위치 args를 포기합니다.

오브젝트(python의 dict와 거의 동일)를 사용하여 인수를 전달할 수 있습니다.

이 예에서는 이미지 파일의 이름을 생성하는 함수를 사용하고 있습니다.

//first we define our function with just ONE argument
function name_of_img(img_desc){

  // with this step, any undefined value will be assigned a value
  if(img_desc.size == undefined) {img_desc.size = "400x500"}
  if(img_desc.format == undefined) {img_desc.format = ".png"}

  console.log(img_desc.size + img_desc.format)
}

//notice inside our function we're passing a dict/object
    
name_of_img({size: "200x250", format=".jpg"})
// returns "200x250.jpg"

name_of_img({size: "1200x950"})
// returns "1200x950.png"

이 예제를 수정하여 positional 인수를 사용할 수도 있고 유효하지 않은 인수를 전달할 수 있도록 수정할 수도 있습니다. 이에 대해 github 저장소를 만들겠습니다.

일반적으로 알려진 것과 달리, 명명된 파라미터는 다음과 같이 단순하고 깔끔한 코딩 규칙을 통해 표준적인 구식 JavaScript(부울 파라미터 전용)에서 구현될 수 있습니다.

function f(p1=true, p2=false) {
    ...
}

f(!!"p1"==false, !!"p2"==true); // call f(p1=false, p2=true)

경고:

  • 인수의 순서는 유지되어야 합니다.단, 이 패턴은 함수 시그니처에 대해 grep를 하거나 IDE를 사용할 필요 없이 어떤 실제 인수가 어떤 형식 파라미터를 의미하는지 알 수 있기 때문에 여전히 유용합니다.

  • 이건 부엉이한테만 먹히는 거야.그러나 JavaScript의 고유한 유형 강제 시멘틱스를 사용하여 다른 유형에서도 유사한 패턴이 개발될 수 있을 것입니다.

언급URL : https://stackoverflow.com/questions/11796093/is-there-a-way-to-provide-named-parameters-in-a-function-call-in-javascript

반응형