메소드 인수의 이름을 지정하는 변수를 정의하는 것이 좋은 방법입니까?


73

가독성을 위해 다음 코드와 같은 함수를 호출하는 동안 임시 변수를 정의하는 경우가 종종 있습니다.

var preventUndo = true;
doSomething(preventUndo);

이것의 짧은 버전은 다음과 같습니다.

doSomething(true);

그러나 코드로 돌아올 때 종종 무엇을 true의미 하는지 궁금 합니다. 이런 종류의 수수께끼에 대한 협약이 있습니까?


5
어떤 종류의 IDE를 사용하십니까? 대부분은 호출하는 함수에 대한 매개 변수가 무엇인지 나타내는 일종의 방법을 사용 하므로이 작업을 수행하지 않아도됩니다.
Matthew Scharley

4
나는 IDE를 사용하지 않지만 힌트조차 일종의 행동 (마우스 오버 또는 라인으로 이동)이 필요할 것이라고 생각합니다. 코드를 보면서 내 코드가 무엇을하는지 알고 싶습니다.
methodofaction

11
언어가 지원하는 경우 다음과 같은 열거 형을 사용할 수 있습니다.doSomething( Undo.PREVENT )
James P.

4
그러나을 정의 할 수 있습니다 Undo = { PREVENT = true, DONT_PREVENT = false }. 그러나 JavaScript에서 관습은 function myFunction( mandatoryArg1, mandatoryArg2, otherArgs ) { /*...*/ }다음과 같이하는 것입니다 myFunction( 1, 2, { option1: true, option2: false } ).
xavierm02

6
언어에 따라 다릅니다. 예를 들어 이것이 파이썬이라면 키워드 인수를 사용하는 것이 좋습니다.doSomething(preventUndo=True)
Joel Cornett

답변:


117

변수 설명

귀하의 경우는 변수 리팩토링을 설명 하는 소개 의 예입니다 . 간단히 말해서 설명 변수는 꼭 필요한 것은 아니지만 가독성을 높이기 위해 명확한 이름을 지정할 수 있습니다.

양질의 코드 는 독자에게 의도 를 전달 합니다. 그리고 전문 개발자로서 가독성과 유지 관리 성이 최고의 목표입니다.

따라서 권장하는 경험 법칙은 다음과 같습니다. 매개 변수의 목적이 명확하지 않은 경우 변수를 사용하여 이름을 지정하십시오. 나는 이것이 일반적으로 좋은 습관이라고 생각합니다 (남용되지 않는 한). 다음은 빠르고 계획적인 예입니다. 다음을 고려하십시오.

editButton.Enabled = (_grid.SelectedRow != null && ((Person)_grid.SelectedRow).Status == PersonStatus.Active);

약간 길지만 분명히 더 명확합니다.

bool personIsSelected = (_grid.SelectedRow != null);
bool selectedPersonIsEditable = (personIsSelected && ((Person)_grid.SelectedRow).Status == PersonStatus.Active)
editButton.Enabled = (personIsSelected && selectedPersonIsEditable);

부울 매개 변수

귀하의 예제는 실제로 API의 부울이나쁜 생각 인지 강조 합니다. 호출 측에서는 무슨 일이 일어나고 있는지 설명하지 않습니다. 치다:

ParseFolder(true, false);

이러한 매개 변수의 의미를 찾아야합니다. 그들이 열거 형이라면 훨씬 분명합니다.

ParseFolder(ParseBehaviour.Recursive, CompatibilityOption.Strict);

편집하다:

너무 많은 사람들이 부울 매개 변수 부분에 집중했기 때문에 제목을 추가하고 두 주요 단락의 순서를 바꿨습니다 (공평하게 말하면 원래 첫 번째 단락 이었습니다 ). 또한 첫 번째 부분에 예제를 추가했습니다.


28
명명 된 매개 변수 (.NET Framework에서 명명 된 인수)를 사용하지 않는 한,이 경우 doSomething(preventUndo: true);는 분명합니다. 또한 API의 모든 부울에 대한 열거 형을 만드시겠습니까? 진심이야?
Arseni Mourzenko

12
@MainMa : 사용하는 언어가 명명 된 인수를 지원하기에 충분하지 않은 경우 열거 형을 사용하는 것이 좋습니다. 이것은 어디서나 열거 형을 체계적으로 소개해야한다는 것을 의미하지는 않습니다.
Giorgio

18
@MainMa-그 질문에 대답하기 위해서는 요점은 API (최소한 공개 API)에 부울이 없어야한다는 것입니다. 명명 된 인수 구문으로 변경해야합니다.이 구문은 (쓰기 시점에서) 관용적이지 않으며 어쨌든 부울 매개 변수는 거의 항상 메서드가 두 가지 작업을 수행한다는 것을 나타내며 호출자가 고르다. 그러나 내 대답의 요점은 코드에서 설명 변수를 사용하는 데 아무런 문제가 없다는 것입니다. 실제로는 아주 좋은 연습입니다.
다니엘 B

3
그것은 C # 언어의 영구적 인 부분입니다. 어떤 "주류 수락"이 더 필요합니까? 구문을 아직 모르는 사람이라도 (C # 개발자가 C # 문서를 읽지 않았 음을 의미), 그것이하는 일이 상당히 분명합니다.
네이트 CK

3
그렇기 때문에 MS가 각 버전에 추가 한 모든 새로운 내용에 대한 요약을 발표하는 이유는 몇 년마다 다음 중 하나를 읽는 데 많은 작업이 필요하지 않다고 생각합니다. msdn.microsoft.com/en- us / library / bb383815 % 28v = vs.100 % 29.aspx
네이트 CK

43

필요없는 코드를 작성하지 마십시오.

doSomething(true)이해하기 어려운 경우 의견을 추가해야합니다.

// Do something and prevent the undo.
doSomething(true);

또는 언어에서 지원하는 경우 매개 변수 이름을 추가하십시오.

doSomething(preventUndo: true);

그렇지 않으면 IDE에 의존하여 호출 된 메소드의 서명을 제공하십시오.

여기에 이미지 설명을 입력하십시오

유용한 경우

추가 변수를 넣는 것이 유용 할 수 있습니다.

  1. 디버깅 목적으로 :

    var productId = this.Data.GetLastProductId();
    this.Data.AddToCart(productId);
    

    동일한 코드를 한 줄로 작성할 수 있지만 제품 ID가 올바른지 확인하기 위해 장바구니에 제품을 추가하기 전에 중단 점을 추가하려는 경우 한 줄 대신 두 줄을 작성하는 것이 좋습니다.

  2. 매개 변수가 많은 방법이 있고 각 매개 변수가 평가에서 나온 경우. 한 줄로, 이것은 완전히 읽을 수 없게 될 수 있습니다.

    // Even with indentation, this is unreadable.
    var doSomething(
        isSomethingElse ? 0 : this.getAValue(),
        this.getAnotherOne() ?? this.default,
        (a + b + c + d + e) * f,
        this.hello ? this.world : (this.hello2 ? this.world2 : -1));
    
  3. 매개 변수 평가가 너무 복잡한 경우 내가 본 코드의 예 :

    // Wouldn't it be easier to have several if/else's (maybe even in a separate method)?
    do(something ? (hello ? world : -1) : (programmers ? stackexchange : (com ? -1 : 0)));
    

다른 경우에는 왜 그렇지 않습니까?

간단한 경우에 추가 변수를 작성하지 않아야하는 이유는 무엇입니까?

  1. 성능 영향 때문이 아닙니다. 이것은 앱을 미세 최적화 하는 초보자 개발자에게는 매우 잘못된 가정 일 것입니다 . 컴파일러가 변수를 인라인하기 때문에 대부분의 언어에서 성능 영향은 없습니다 . 컴파일러가 그렇게하지 않는 언어에서는 직접 손으로 인라인하여 몇 마이크로 초를 얻을 수 있습니다. 하지마

  2. 그러나 변수에 부여한 이름을 매개 변수 이름과 분리 할 위험이 있습니다.

    예:

    원래 코드는 다음과 같습니다.

    void doSomething(bool preventUndo)
    {
        // Does something very interesting.
        undoHistory.removeLast();
    }
    
    // Later in code:
    var preventUndo = true;
    doSomething(preventUndo);
    

    나중에 개발자 doSomething는 최근 실행 취소 기록에 두 가지 새로운 방법이 도입되었음을 알았습니다.

    undoHistory.clearAll() { ... }
    undoHistory.disable() { ... }
    

    이제는 preventUndo명확하지 않은 것 같습니다. 마지막 조치 만 방지한다는 의미입니까? 아니면 사용자가 더 이상 실행 취소 기능을 사용할 수 없다는 의미일까요? 아니면 취소 기록이 지워질까요? 명확한 이름은 다음과 같습니다.

    doSomething(bool hideLastUndo) { ... }
    doSomething(bool removeAllUndo) { ... }
    doSomething(bool disableUndoFeature) { ... }
    

    이제 다음이 있습니다.

    void doSomething(bool hideLastUndo)
    {
        // Does something very interesting.
        undoHistory.removeLast();
    }
    
    // Later in code, very error prone, while the signature of the method is clear:
    var preventUndo = true;
    doSomething(preventUndo);
    

열거 형은 어떻습니까?

다른 사람들은 열거 형을 사용하도록 제안했습니다. 즉각적인 문제를 해결하는 동안 더 큰 문제를 만듭니다. 한 번 보자:

enum undoPrevention
{
    keepInHistory,
    prevent,
}

void doSomething(undoPrevention preventUndo)
{
    doTheJob();
    if (preventUndo == undoPrevention.prevent)
    {
        this.undoHistory.discardLastEntry();
    }
}

doSomething(undoPrevention.prevent);

그 문제 :

  1. 너무 많은 코드입니다. if (preventUndo == undoPrevention.prevent)? 진심이야?! 나는 if매번 그런 것들을 쓰고 싶지 않습니다 .

  2. 다른 곳에서 동일한 열거 형을 사용하는 경우 나중에 열거 형에 요소를 추가하는 것이 매우 유혹적입니다. 이렇게 수정하면 어떻게 되나요?

    enum undoPrevention
    {
        keepInHistory,
        prevent,
        keepButDisable, // Keeps the entry in the history, but makes it disabled.
    }
    

    이제 어떻게 될까요? 윌 doSomething방법 작업은 예상대로? 이를 방지하기 위해이 방법을 처음부터 다음과 같이 작성해야합니다.

    void doSomething(undoPrevention preventUndo)
    {
        if (![undoPrevention.keepInHistory, undoPrevention.prevent].contains(preventUndo))
        {
            throw new ArgumentException('preventUndo');
        }
    
        doTheJob();
        if (preventUndo == undoPrevention.prevent)
        {
            this.undoHistory.discardLastEntry();
        }
    }
    

    부울을 사용하는 변형이 너무 좋아 보이기 시작합니다!

    void doSomething(bool preventUndo)
    {
        doTheJob();
        if (preventUndo)
        {
            this.undoHistory.discardLastEntry();
        }
    }
    

3
"이것은 너무 많은 코드입니다. if (preventUndo == undoPrevention.prevent)? 진지하게?! 매번 그런 ifs를 작성하고 싶지 않습니다." 또한 부울을 사용하는 경우 어쨌든 if 문이 필요합니다. 솔직히이 점에 대한 당신의 비판은 나에게 약간 인공적인 것 같습니다.
Giorgio

1
다른 해결책이 없습니다. 당신은 그가 아무 말도하지 않는 진실하고 거짓된 것을 고수하고 IDE (그가 사용하지 않는)에 의존해야한다고 말하는가? 주석은 변수 이름처럼 썩을 수 있습니다.
11:23에

2
@ superM : 호출에만 사용되는 임시 변수의 이름을 변경하는 것이 훨씬 어렵습니다. 열거 형 이름이 변경되면 호출 코드가 더 이상 실행되지 않고 얼굴에 오류가 발생하기 때문에 더 좋습니다. 함수의 기능이 열거 확장에 의해 근본적으로 변경되면 추가 정확성을 위해 모든 호출을 다시 방문해야합니다. 그렇지 않으면 논리가 아닌 희망에 따라 프로그래밍해야합니다. 부정 예를 들어, 값을 변경하는 방법에 대한조차 생각하기 preventUndoallowUndo... 서명에
보안

4
코드와 동기화 된 주석을 유지하는 @superM은 실제로 불일치를 찾기 위해 컴파일러의 도움이 없기 때문에 문제가 발생하기 쉽습니다.
Buhb

7
"... 호출 된 메소드의 서명을 제공하기 위해 IDE에 의존"-코드를 작성할 때 유용하지만 코드를 읽을 때는 그다지 유용하지 않습니다. 클래스의 코드를 읽을 때 클래스를 보면서 무엇을하고 있는지 알고 싶습니다. 가독성을 위해 IDE에 의존해야하는 경우 코드는 자체 문서화가 아닙니다.
Phil

20

또한 부울 플래그가있는 메소드를 작성해서는 안됩니다.

Robert C. Martin은 자신의 저서 Clean Code (ISBN-13 978-0-13-235088-4)에서 "부울을 함수에 전달하는 것은 정말 끔찍한 관행"이라고 말합니다.

그를 역설하면, 당신이 참 / 거짓 스위치를 가지고 있다는 것은 당신의 방법이 두 가지 다른 일을 할 가능성이 높다는 것을 의미하기 때문에 (즉, "실행 취소로 무언가를한다"와 "실행 취소없이 무언가를한다") 내부적으로 동일한 것을 호출 할 수있는 두 가지 다른 방법으로 나눕니다.

DoSomething()
{...

DoSomethingUndoable()
{....

7
이 논리에 따라 내 단일 HotDog 생성자는 약 16 개의 다른 메소드가 필요합니다. HotDogWithMustardRelishKrautOnion (), HotDogWithMustardNorelishKrautOnion () 등. 또는 옵션을 비트 필드로 해석하는 간단한 HotDogWithOptions (int options) 일 수 있지만 다른 것으로 의심되는 여러 가지 작업을 수행하는 한 가지 방법으로 돌아갑니다. 따라서 첫 번째 옵션을 사용하는 경우 부울 매개 변수였던 항목을 기반으로 호출 할 생성자를 정렬하려면 큰 조건을 작성해야합니까? 그리고 Q가 int를 사용한다면,이 A는 Q에 대답하지 않습니다.
Caleb

4
모든 답변을 읽고 내 코드를 본 후에 이것이 올바른 방법이라는 결론에 도달했습니다. doSomethingUndoable()변경 사항을 캡처하고 부를 수doSomething()
methodofaction

1
따라서 많은 처리 작업을 수행하고 이메일을 보낼 때 이메일을 보낼 수있는 옵션이있는 경우 이메일을 보내지 못하게하는 부울 인수가 없어야 별도의 함수를 만들어야합니까?
yakatz

2
@Caleb이 경우 핫도그를 만들고 재료를 하나씩 추가하거나 강력한 형식의 언어로 모든 부울 플래그를 설정 한 HotDogSettings 객체를 전달합니다. 나는 유지해야 할 악몽이 될 15 가지 다른 true / false 플래그가 없을 것입니다. 코드는 작성 비용이 아니라 유지 관리에 관한 것임을 기억하십시오. 응용 프로그램 비용의 80 %입니다. var hd = MakeHotDog (); hd.Add (양파); ...
Nick B.

2
@Caleb 필자의 예는 부울을 실제 데이터 필드로 사용하지만 대부분의 용도는 실행 흐름을 유도하는 것입니다. 따라서 밥 아저씨가 그것에 대한 난간입니다. 또한, 그의 조언은 극단적 인 측면에 있습니다.이 책의 다음 몇 줄은 2 개 이상의 매개 변수를 사용하지 않는 것이 좋습니다. 그러나 광기에 방법이 있습니다. 그래도 질문에 답하지 못하는 것은 내 자신의 대답에서 실수 한 것입니다.
Daniel B

5

두 클래스가 어떻게 결합되어 있는지 살펴보면 카테고리 중 하나 는 데이터 커플 링입니다 .이 클래스는 한 클래스에서 다른 클래스의 메소드를 호출하고 보고서를 원하는 달과 같은 데이터를 전달하는 코드를 나타냅니다. category는 control coupling , 메소드 호출 및 메소드의 동작을 제어하는 ​​무언가를 전달하는 것입니다. 클래스에서 사용하는 예제는 verbose플래그 또는 reportType플래그이지만 preventUndo훌륭한 예제입니다. 방금 시연 한 것처럼 제어 커플 링은 호출 코드를 읽고 무슨 일이 일어나고 있는지 이해하기 어렵게 만듭니다. 또한 doSomething()동일한 플래그를 사용하여 실행 취소 및 보관을 제어하거나 다른 매개 변수를 추가 하는 변경 사항에 대해 호출 코드를 취약하게 만듭니다.doSomething() 보관을 제어하여 코드를 깨는 등의 작업을 수행합니다.

문제는 코드가 너무 밀접하게 결합되어 있다는 것입니다. 내 의견으로는 행동을 제어하기 위해 부울을 전달하는 것은 나쁜 API의 표시입니다. API를 소유 한 경우 변경하십시오. 두 가지 방법, doSomething()그리고 doSomethingWithUndo()더 나은 것입니다. 소유하고 있지 않은 경우, 소유하고있는 코드에 두 개의 랩퍼 메소드를 직접 작성하고 그 중 하나를 호출 doSomething(true)하고 다른 하나를 호출하십시오 doSomething(false).


4

인수의 역할을 정의하는 것은 호출자의 역할이 아닙니다. 나는 항상 인라인 버전으로 가서 의심스러운 경우 호출 된 함수의 서명을 확인합니다.

변수는 현재 범위에서 해당 역할의 이름을 따라야합니다. Not 전송 된 범위입니다.


1
현재 범위에서 변수의 역할은 변수의 용도를 알려주는 것입니다. 이것이 OP의 임시 변수 사용과 어떻게 모순되는지는 알 수 없습니다.
superM

4

JavaScript에서 할 일은 함수가 다음과 같은 유일한 매개 변수로 객체를 가져 오는 것입니다.

function doSomething(settings) {
    var preventUndo = settings.hasOwnProperty('preventUndo') ? settings.preventUndo : false;
    // Deal with preventUndo in the normal way.
}

그런 다음 전화하십시오.

doSomething({preventUndo: true});

하아!!! 우리 둘 다 doSomething(x)방법을 만들었습니다 ! 롤 ... 지금까지 당신의 게시물을 보지 못했습니다.
blesh

문자열 "noUndo"를 전달하면 어떻게됩니까? 서명을 사용하는 사람이 구현을 조사하지 않고 어떤 설정을 포함해야하는지 명확합니까?
Nick B.

1
코드를 문서화하십시오. 다른 사람들이하는 일입니다. 한 번만 수행하면 코드를보다 쉽게 ​​읽을 수 있습니다.
ridecar2

1
@NickB. 컨벤션은 강력합니다. 대부분의 코드에서 인수가있는 객체를 받아들이면 분명합니다.
orip

4

나는 명확성을 돕기 위해 언어 기능을 활용하는 것을 좋아합니다. 예를 들어 C #에서는 이름으로 매개 변수를 지정할 수 있습니다.

 CallSomething(name: "So and so", age: 12, description: "A random person.");

JavaScript에서는 일반적으로 이러한 이유로 인수로 옵션 객체를 사용하는 것을 선호합니다.

function doSomething(args) { /*...*/ }

doSomething({ name: 'So and so', age: 12, description: 'A random person.' });

그래도 내 취향입니다. 호출 된 메소드와 개발자가 서명을 이해하는 데 IDE가 어떻게 도움이되는지에 크게 의존한다고 가정합니다.


1
그것은 느슨하게 입력 된 언어의 "단점"입니다. 유효성 검사 없이는 실제로 서명을 시행 할 수 없습니다. JS에서 그런 이름을 추가 할 수 있다는 것을 몰랐습니다.
James P.

1
@JamesPoulson : 당신은 아마도 당신이 JS에서 그것을 할 수 있다는 것을 알고 아마 그것을 깨닫지 못했습니다. 그것은 JQuery에서 끝났습니다 : $.ajax({url:'', data:''})etc.
blesh

참된. 언뜻보기에는 드문 것 같지만 일부 언어로 존재할 수있는 인라인 의사 객체와 유사합니다.
제임스 P.

3

나는 이것이 가장 간단하고 읽기 쉽다는 것을 알았습니다.

enum Undo { ALLOW, PREVENT }

doSomething(Undo u) {
    if (Undo.ALLOW == u) {
        // save stuff to undo later.
    }
    // do your thing
}

doSomething(Undo.ALLOW);

MainMa는 그것을 좋아하지 않습니다. 동의하지 않을 수도 있고 Joshua Bloch가 제안한 솔루션을 사용할 수도 있습니다.

enum Undo {
    ALLOW {
        @Override
        public void createUndoBuffer() {
            // put undo code here
        }
    },
    PREVENT {
        @Override
        public void createUndoBuffer() {
            // do nothing
        }
    };

    public abstract void createUndoBuffer();
}

doSomething(Undo u) {
    u.createUndoBuffer();
    // do your thing
}

이제 Undo.LIMITED_UNDO를 추가하면 createUndoBuffer () 메소드를 구현하지 않으면 코드가 컴파일되지 않습니다. 그리고 doSomething ()에는 if (Undo.ALLOW == u)가 없습니다. 두 가지 방법을 모두 수행했으며 두 번째 방법은 매우 무겁고 Undo 열거 형이 페이지 및 코드 페이지로 확장 될 때 이해하기가 약간 어렵지만 생각합니다. 나는 보통 변경해야 할 때까지 간단한 부울을 2 값 열거 형으로 대체하는 더 간단한 방법을 고수합니다. 세 번째 값을 추가하면 IDE를 사용하여 "사용처 찾기"하고 모든 것을 수정합니다.


2

귀하의 솔루션이 코드를 좀 더 읽기 쉽게 만든다고 생각하지만 함수 호출을보다 명확하게하기 위해 추가 변수를 정의하지 마십시오. 또한 추가 변수를 사용하려면 프로그래밍 언어에서 지원하는 경우 상수로 표시합니다.

추가 변수를 포함하지 않는 두 가지 대안을 생각할 수 있습니다.

1. 추가 의견을 사용하십시오

doSomething(/* preventUndo */ true);

2. 부울 대신 2 값 열거 형을 사용하십시오.

enum Options
{
    PreventUndo,
    ...
}

...

doSomething(PreventUndo);

언어가 열거 형을 지원하는 경우 대안 2를 사용할 수 있습니다.

편집하다

물론 언어에서 지원하는 경우 명명 된 인수를 사용하는 것도 옵션입니다.

열거 형에 필요한 추가 코딩과 관련하여 실제로 무시할 수있는 것처럼 보입니다. 대신에

if (preventUndo)
{
    ...
}

당신은 가지고

if (undoOption == PreventUndo)
{
    ...
}

또는

switch (undoOption)
{
  case PreventUndo:
  ...
}

조금 더 타이핑하더라도 코드가 한 번 작성되고 여러 번 읽히므로 6 개월 후에 더 읽기 쉬운 코드를 찾기 위해 조금 더 타이핑하는 것이 좋습니다.


2

@GlenPeterson의 말에 동의합니다.

doSomething(Undo.ALLOW); // call using a self evident enum

그러나 두 가지 가능성 (true 또는 false)이있는 것처럼 보이기 때문에 신비로운 것은 다음과 같습니다.

//Two methods    

doSomething()  // this method does something but doesn't prevent undo

doSomethingPreventUndo() // this method does something and prevents undo

2
좋은 생각-나는 그것을 생각하지 않았다. doSomething (String, String, String, boolean, boolean, boolean)과 같이 더 복잡해지면 명명 된 상수가 유일한 합리적인 솔루션입니다. Josh Bloch는 다음과 같이 팩토리 및 생성자 객체를 제안합니다. MyThingMaker thingMaker = MyThingMaker.new (); thingMaker.setFirstString ( "Hi"); thingMaker.setSecondString ( "There"); etc ... Thing t = thingMaker.makeIt (); t.doSomething (); 그것은 훨씬 더 많은 일이므로 가치가 더 낫습니다.
GlenPeterson

후자의 접근 방식의 한 가지 문제점 doSomething은 호출자가 실행 취소 허용 여부를 선택할 수 있지만 사용하는 메소드를 작성하는 것이 어색하다는 것 입니다. 해결 방법은 부울 옵션을 사용하는 오버로드가 있지만 매개 변수가 항상 true 또는 항상 false 인 이전 버전을 호출하는 래퍼 버전을 갖는 것일 수도 있습니다.
supercat

@GlenPeterson 팩토리는 가능성이 있으며 Javascript (OP에 의해 언급 됨)에서 가능합니다.
James P.

2

주로 자바 스크립트에 대해 질문하기 때문에 커피 스크립트를 사용하면 구문과 같은 명명 된 인수를 사용할 수 있습니다.

# declare method, ={} declares a default value to prevent null reference errors
doSomething = ({preventUndo} = {}) ->
  if preventUndo
    undo = no
  else
    undo = yes

#call method
doSomething preventUndo: yes
#or 
doSomething(preventUndo: yes)

컴파일

var doSomething;

doSomething = function(_arg) {
  var preventUndo, undo;
  preventUndo = (_arg != null ? _arg : {}).preventUndo;
  if (preventUndo) {
    return undo = false;
  } else {
    return undo = true;
  }
};

doSomething({
  preventUndo: true
});

doSomething({
  preventUndo: true
});

http://js2coffee.org/ 에서 재미있게 보내십시오.


javascript의 OOP 광기를 피해야 할 때만 coffeeScript를 사용합니다. 이것은 혼자 코딩 할 때 사용할 수있는 훌륭한 솔루션입니다. 가독성을 위해 부울 대신 객체를 전달한다는 것을 동료에게 정당화하는 것은 어렵습니다!
methodofaction

1

덜 일반적인 솔루션과 OP가 Javascript를 언급했기 때문에 값을 매핑하기 위해 연관 배열을 사용할 수 있습니다. 단일 부울에 대한 장점은 원하는만큼 많은 인수를 가질 수 있고 시퀀스에 대해 걱정하지 않아도된다는 것입니다.

var doSomethingOptions = new Array();

doSomethingOptions["PREVENTUNDO"] = true;
doSomethingOptions["TESTMODE"] = false;

doSomething( doSomethingOptions );

// ...

function doSomething( doSomethingOptions ){
    // Check for null here
    if( doSomethingOptions["PREVENTUNDO"] ) // ...
}

나는 이것이 강하게 타이핑 된 배경을 가진 누군가의 반사이며, 실용적이지는 않지만 독창성을 위해 이것을 고려합니다.

또 다른 가능성은 객체를 갖는 것이며 Javascript에서도 가능합니다. 이것이 구문 적으로 올바른지 100 % 확신하지 못합니다. 더 영감을 얻으려면 Factory와 같은 패턴을 살펴보십시오.

function SomethingDoer( preventUndo ) {
    this.preventUndo = preventUndo;
    this.doSomething = function() {
            if( this.preventUndo ){
                    // ...
            }
    };
}

mySomethingDoer = new SomethingDoer(true).doSomething();

1
나는 이것이 doSomethingOptions.PREVENTUNDO배열 액세스 표기법 대신 점 표기법 ( ) 으로 더 잘 작성 될 수 있다고 생각합니다 .
Paŭlo Ebermann

1

귀하의 질문과 다른 답변의 초점은 함수가 호출되는 가독성을 향상시키는 것입니다. "부울 인수 없음"이벤트와 같은 특정 지침은 항상이 목적을위한 수단으로 기능해야하며 스스로 끝나지 않아야합니다.

프로그래밍 언어가 C # 4 및 Python과 같이 명명 된 인수 / 키워드 인수를 지원하거나 Smalltalk 또는 Objective-C와 같이 메소드 이름에 메소드 인수가 인터리브되는 경우이 문제는 대부분 회피되는 것이 유용하다고 생각합니다.

예 :

// C# 4
foo.doSomething(preventUndo: true);
# Python
foo.doSomething(preventUndo=True)
// Objective-C
[foo doSomethingWith:bar shouldPreventUndo:YES];

0

부울 변수를 함수의 인수로 전달하지 않아야합니다. 함수는 한 번에 한 가지 작업을 수행해야하기 때문입니다. 부울 변수를 전달하면 함수에 두 가지 동작이 있습니다. 또한 나중 단계 나 코드를 보는 경향이있는 다른 프로그래머에게도 가독성 문제가 발생합니다. 또한 함수를 테스트 할 때 문제가 발생합니다. 이 경우 아마도 두 개의 테스트 케이스를 작성해야합니다. switch 문을 가지고 있고 스위치 유형에 따라 동작을 변경하는 함수가 있다고 가정하면 너무 많은 테스트 사례를 정의해야한다고 상상해보십시오.

함수에 대한 부울 인수를 가질 때마다 부울 인수를 전혀 쓰지 않도록 코드를 조정해야합니다.


따라서 코드의 작은 부분 (원본이있는 곳)에서만 다른 두 함수에서 부울 인수가있는 함수를 변환 if(param) {...} else {...}합니까?
Paŭlo Ebermann

-1
int preventUndo = true;
doSomething(preventUndo);

C ++과 같은 낮은 수준의 언어에 적합한 컴파일러는 다음과 같이 2 줄 이상의 머신 코드를 최적화합니다.

doSomething(true); 

성능에는 문제가되지 않지만 가독성이 향상됩니다.

또한 나중에 변수가되고 다른 값도 받아 들일 수있는 경우 변수를 사용하는 것이 좋습니다.

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