여러 인수와 옵션 개체


157

여러 인수로 JavaScript 함수를 만들 때 항상이 선택에 직면합니다. 인수 목록 전달과 옵션 개체 전달.

예를 들어 nodeList를 배열에 매핑하는 함수를 작성하고 있습니다.

function map(nodeList, callback, thisObject, fromIndex, toIndex){
    ...
}

대신 이것을 사용할 수 있습니다 :

function map(options){
    ...
}

여기서 options는 객체입니다.

options={
    nodeList:...,
    callback:...,
    thisObject:...,
    fromIndex:...,
    toIndex:...
}

어느 것이 권장되는 방법입니까? 한 대를 사용하는시기에 대한 지침이 있습니까?

[업데이트] 옵션 객체에 찬성하여 합의가있는 것 같습니다. 따라서 의견을 추가하고 싶습니다. 필자의 경우 인수 목록을 사용하려는 유혹을받는 한 가지 이유는 JavaScript와 일치하는 동작을 갖는 것이 었습니다 내장 된 array.map 메소드.


2
두 번째 옵션은 명명 된 인수를 제공하는데, 제 생각에는 좋은 것입니다.
Werner Kvalem Vesterås

선택적 또는 필수 인수입니까?
나는

내 예제에서 @ user1689607 마지막 세 개는 선택 사항입니다.
Christophe

마지막 두 개의 인수는 매우 유사하기 때문에 사용자가 하나만 전달하면 어떤 것이 의도되었는지 알 수 없습니다. 이 때문에 거의 명명 된 인수가 필요합니다. 그러나 네이티브 API와 비슷한 API를 유지하고 싶다는 점을 이해할 수 있습니다.
나는 19:51에 게으른

1
함수가 비슷한 작업을 수행하는 경우 기본 API를 사용한 모델링은 나쁘지 않습니다. "코드를 가장 많이 읽는 이유"로 귀결됩니다. Array.prototype.map세미 경험이있는 코더를 당황하게하지 않아야하는 간단한 API가 있습니다.
Jeremy J Starcher

답변:


160

다른 많은 것들과 마찬가지로, 나는 options object긴 매개 변수 목록을 전달하는 대신 함수에 전달하는 것을 선호 하지만 실제로는 정확한 컨텍스트에 달려 있습니다.

리트머스 테스트로 코드 가독성을 사용합니다.

예를 들어,이 함수 호출이 있으면 :

checkStringLength(inputStr, 10);

코드를 읽을 수 있고 개별 매개 변수를 전달하는 것이 좋습니다.

반면에 다음과 같은 호출 기능이 있습니다.

initiateTransferProtocol("http", false, 150, 90, null, true, 18);

조사하지 않으면 완전히 읽을 수 없습니다. 반면에이 코드는 다음과 같이 잘 읽습니다.

initiateTransferProtocol({
  "protocol": "http",
  "sync":      false,
  "delayBetweenRetries": 150,
  "randomVarianceBetweenRetries": 90,
  "retryCallback": null,
  "log": true,
  "maxRetries": 18
 });

그것은 과학보다는 예술에 가깝지만 규칙의 이름을 정해야한다면 :

다음과 같은 경우 옵션 매개 변수를 사용하십시오.

  • 네 개 이상의 매개 변수가 있습니다
  • 모든 매개 변수는 선택 사항입니다
  • 어떤 매개 변수가 필요한지 알아 내기 위해 함수를 찾아야했습니다.
  • 누군가가 "ARRRRRG!"

10
좋은 대답입니다. 때에 따라 다르지. 부울 트랩주의 ariya.ofilabs.com/2011/08/hall-of-api-shame-boolean-trap.html
Trevor Dixon

2
아 맞다. 나는 그 링크를 잊었다. API가 어떻게 작동하는지 다시 생각하게 만들었고 바보 같은 일을 한 후에도 몇 가지 코드를 다시 작성했습니다. 감사!
Jeremy J Starcher

1
'필요한 매개 변수를 파악하기 위해 함수를 찾아야했습니다.'-옵션 개체를 대신 사용하면 항상 키가 필요한지, 키가 무엇인지 파악할 수있는 방법을 찾지 않아도됩니다. IDE의 Intellisense는이 정보를 표시하지 않지만 매개 변수는 표시합니다. 대부분의 IDE에서 단순히 메소드 위로 마우스를 가져 가면 매개 변수가 무엇인지 보여줍니다.
simbolo

1
너희들이 '베스트 프랙티스를 코딩'의이 비트의 성능 결과에 관심이 있다면, 여기에 두 가지를 점검 방법 jsPerf입니다 : jsperf.com/function-boolean-arguments-vs-options-object/10 주에게의 약간의 트위스트 세 번째 대안, '프리셋'(일정한) 옵션 객체를 사용하는 경우 개발 시간에 알려진 동일한 설정으로 (예를 들어 웹 페이지와 같은 런타임 동안) 호출이 많은 경우 수행 할 수 있습니다. : 옵션 값이 소스 코드에 하드 코딩 된 경우).
Ger Hobbelt

2
@Sean 솔직히, 나는 더 이상이 스타일의 코딩을 전혀 사용하지 않습니다. TypeScript로 전환하고 명명 된 매개 변수를 사용했습니다.
Jeremy J Starcher

28

여러 인수는 주로 필수 매개 변수에 대한 것입니다. 그들에게는 아무런 문제가 없습니다.

선택적 매개 변수가 있으면 복잡해집니다. 그들 중 하나가 다른 것에 의존하여 특정 순서를 갖도록 (예를 들어 네 번째 것은 세 번째 것을 필요로하는 경우), 여전히 여러 개의 인수를 사용해야합니다. 거의 모든 기본 EcmaScript 및 DOM 메소드가 이와 같이 작동합니다. openXMLHTTPrequests 방법 이 좋은 예입니다. 마지막 3 개의 인수는 선택 사항입니다. 규칙은 "사용자가없는 암호 없음"과 같습니다 ( MDN 문서 참조 ).

옵션 객체는 두 가지 경우에 유용합니다.

  • 혼동 될 수있는 매개 변수가 너무 많습니다. "이름 지정"이 도움이되며 순서에 대해 걱정할 필요가 없습니다 (특히 변경 될 수있는 경우).
  • 선택적 매개 변수가 있습니다. 객체는 매우 융통성이 있으며, 순서가 없으면 필요한 것만 전달하고 다른 것 (또는 undefineds) 은 전달하지 않습니다 .

귀하의 경우을 추천 map(nodeList, callback, options)합니다. nodelist그리고 callback다른 세 개의 인수는 가끔 와서 적절한 기본값을 가지고해야합니다.

또 다른 예는 JSON.stringify입니다. 함수 space를 전달하지 않고 매개 변수 를 사용하고 싶을 수도 있습니다 . replacer그런 다음 호출해야합니다 …, null, 4). 인수 오브젝트는 2 개의 매개 변수에만 실제로 적합하지는 않지만 더 좋을 수 있습니다.


@ trevor-dixon과 +1 같은 질문 : 예를 들어 js 라이브러리에서 실제로 사용되는 혼합을 보셨습니까?
Christophe

예를 들어 jQuery의 ajax 메소드가 있습니다. 그들은 [필수] URL을 첫 번째 인수로, 큰 옵션 인수를 두 번째 인수로 허용합니다.
Bergi

그래서 이상한! 나는 전에 이것을 본 적이 없다. 나는 항상 옵션 속성으로 URL과 함께 사용되는 것을 보았습니다 ...
Christophe

예, jQuery는 이전 버전과의 호환성을 유지하면서 선택적 매개 변수를 사용하여 이상한 일을합니다 :-)
Bergi

1
제 생각에는 이것이 유일한 정답입니다.
Benjamin Gruenbaum

11

'객체로서의 옵션'접근법을 사용하는 것이 가장 좋습니다. 속성 순서에 대해 걱정할 필요가 없으며 데이터가 전달 될 때 더 많은 유연성이 있습니다 (예 : 선택적 매개 변수).

객체를 생성하면 옵션을 여러 기능에서 쉽게 사용할 수 있습니다.

options={
    nodeList:...,
    callback:...,
    thisObject:...,
    fromIndex:...,
    toIndex:...
}

function1(options){
    alert(options.nodeList);
}

function2(options){
    alert(options.fromIndex);
}

여기서 (합리적인) 가정은 객체가 항상 같은 키 페어를 가질 것이라는 것입니다. 쓰레기 / 일관되지 않은 API로 작업하는 경우 다른 문제가 있습니다.
backdesk

9

무언가를 인스턴스화하거나 객체의 메소드를 호출하는 경우 옵션 객체를 사용하고 싶다고 생각합니다. 하나 또는 두 개의 매개 변수에서만 작동하고 값을 반환하는 함수 인 경우 인수 목록이 바람직합니다.

어떤 경우에는 두 가지를 모두 사용하는 것이 좋습니다. 함수에 하나 또는 두 개의 필수 매개 변수와 여러 개의 선택적 매개 변수가있는 경우, 처음 두 개의 매개 변수를 필요로하고 세 번째는 선택적 옵션 해시로 만드십시오.

귀하의 예에서 나는 할 것 map(nodeList, callback, options)입니다. 노드 목록과 콜백이 필요하며 호출을 읽는 것만으로도 상황을 쉽게 알 수 있으며 기존 맵 함수와 같습니다. 다른 옵션은 선택적 세 번째 매개 변수로 전달할 수 있습니다.


흥미로운 +1 js 라이브러리와 같이 실제로 사용되는 것을 보셨습니까?
Christophe

7

질문에 대한 귀하의 의견 :

이 예에서 마지막 3 개는 선택 사항입니다.

그럼 왜 안 해? (참고 : 이것은 상당히 원시적 인 자바 스크립트입니다. 일반적으로 default해시를 사용하고 Object.extend 또는 JQuery.extend 등 을 사용하여 전달 된 옵션으로 업데이트합니다 .)

function map(nodeList, callback, options) {
   options = options || {};
   var thisObject = options.thisObject || {};
   var fromIndex = options.fromIndex || 0;
   var toIndex = options.toIndex || 0;
}

이제 선택 사항과 그렇지 않은 사항이 훨씬 분명해 졌으므로 이러한 기능은 모두 유효합니다.

map(nodeList, callback);
map(nodeList, callback, {});
map(nodeList, callback, null);
map(nodeList, callback, {
   thisObject: {some: 'object'},
});
map(nodeList, callback, {
   toIndex: 100,
});
map(nodeList, callback, {
   thisObject: {some: 'object'},
   fromIndex: 0,
   toIndex: 100,
});

이것은 @ trevor-dixon의 답변과 비슷합니다.
Christophe

5

이 답변으로 파티에 조금 늦을 수도 있지만이 주제에 대한 다른 개발자의 의견을 찾고 있었고이 스레드를 발견했습니다.

나는 대부분의 응답자들에 동의하지 않으며 '다중 논쟁'접근법과 관련이 있습니다. 나의 주요 주장은 "param 객체의 변경과 반환"또는 "같은 param 객체를 다른 함수에 전달"과 같은 다른 안티 패턴을 사용하지 않는 것입니다. 나는이 안티 패턴을 광범위하게 악용 한 코드베이스에서 일했으며, 이것을하는 디버깅 코드는 빠르게 불가능합니다. Javascript는 강력하게 유형이 지정되지 않았으며 임의로 구조화 된 객체를 허용하기 때문에 이것은 매우 Javascript 고유의 경험 법칙이라고 생각합니다.

필자의 개인적인 의견은 개발자가 함수를 호출 할 때 명시 적이어야하며 중복 데이터를 전달하지 않고 참조 기준 수정을 피해야한다는 것입니다. 이 패턴이 간결하고 정확한 코드 작성을 방해하는 것은 아닙니다. 프로젝트가 나쁜 개발 관행에 훨씬 쉽게 빠질 수 있다고 생각합니다.

다음과 같은 끔찍한 코드를 고려하십시오.

function main() {
    const x = foo({
        param1: "something",
        param2: "something else",
        param3: "more variables"
    });

    return x;
}

function foo(params) {
    params.param1 = "Something new";
    bar(params);
    return params;
}


function bar(params) {
    params.param2 = "Something else entirely";
    const y = baz(params);
    return params.param2;
}

function baz(params) {
    params.params3 = "Changed my mind";
    return params;
}

이러한 종류의 의도를 명시하기 위해서는보다 명확한 문서가 필요할뿐만 아니라 모호한 오류가 발생할 여지가 있습니다. 어떤 개발자 수정하는 경우 param1bar() ? 이것을 포착하기 위해 충분한 크기의 코드베이스를 살펴 보는 데 얼마나 걸립니까? 물론,이 예제는 개발자들이이 시점에서 이미 여러 가지 안티 패턴을 커밋했다고 가정하기 때문에 약간 불분명합니다. 그러나 매개 변수를 포함하는 객체를 전달하면 오류와 모호성이 더 커질 수 있으며 양심 성과 const 정확성의 준수가 더 필요한 방법을 보여줍니다.

이 문제에 대한 나의 2 센트!


3

때에 따라 다르지.

인기있는 라이브러리 디자인에 대한 나의 관찰을 바탕으로 옵션 객체를 사용해야하는 시나리오는 다음과 같습니다.

  • 매개 변수 목록이 길다 (> 4).
  • 일부 또는 모든 매개 변수는 선택 사항이며 특정 순서에 의존하지 않습니다.
  • 향후 API 업데이트에서 매개 변수 목록이 커질 수 있습니다.
  • API가 다른 코드에서 호출되며 API 이름이 매개 변수의 의미를 알기에 명확하지 않습니다. 따라서 가독성을 위해 강력한 매개 변수 이름이 필요할 수 있습니다.

매개 변수 목록을 사용하는 시나리오 :

  • 매개 변수 목록이 짧습니다 (<= 4).
  • 대부분 또는 모든 매개 변수가 필요합니다.
  • 선택적 매개 변수는 특정 순서로되어 있습니다. (예 : $ .get)
  • API 이름으로 매개 변수 의미를 쉽게 알 수 있습니다.

2

객체를 전달하면 해당 객체의 속성을 쉽게 확장 할 수 있으며 인수가 전달 된 순서를 감시 할 필요가 없기 때문에 객체가 더 바람직합니다.


1

일반적으로 사전 정의 된 인수를 사용하는 함수의 경우 옵션 오브젝트를 사용하는 것이 좋습니다. 반대의 예는 setCSS ({height : 100}, {width : 200}, {background : "# 000"})와 같이 무한한 수의 인수를받는 함수와 같습니다.


0

큰 자바 스크립트 프로젝트를 보았습니다.

구글 맵과 같은 것은 인스턴스화 된 객체에는 객체가 필요하지만 함수에는 매개 변수가 필요하다는 것을 자주 알 수 있습니다. 나는 이것이 OPTION 인수와 관련이 있다고 생각합니다.

기본 인수 또는 선택적 인수가 필요한 경우 객체가 더 유연하기 때문에 더 좋습니다. 그러나 정상적인 기능 인수가 아니라면 더 분명합니다.

자바 스크립트에도 arguments객체가 있습니다. https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.