인수가 JavaScript 함수로 전송되지 않는지 확인하는 가장 좋은 방법


236

이제 인수가 JavaScript 함수에 전달되었는지 확인하는 두 가지 방법을 보았습니다. 한 방법이 다른 방법보다 낫거나 사용하기가 나쁜지 궁금합니다.

 function Test(argument1, argument2) {
      if (Test.arguments.length == 1) argument2 = 'blah';

      alert(argument2);
 }

 Test('test');

또는

 function Test(argument1, argument2) {
      argument2 = argument2 || 'blah';

      alert(argument2);
 }

 Test('test');

내가 알 수있는 한, 둘 다 동일한 결과를 얻지 만 생산에서 처음 하나만 사용했습니다.

Tom이 언급 한 다른 옵션 :

function Test(argument1, argument2) {
    if(argument2 === null) {
        argument2 = 'blah';
    }

    alert(argument2);
}

Juan의 의견에 따라 Tom의 제안을 다음과 같이 변경하는 것이 좋습니다.

function Test(argument1, argument2) {
    if(argument2 === undefined) {
        argument2 = 'blah';
    }

    alert(argument2);
}

정말 동일합니다. 항상 고정 된 수의 인수가있는 경우 두 번째 방법을 사용하십시오. 그렇지 않으면 arguments 배열을 사용하여 반복하는 것이 더 쉽습니다.
Luca Matteis

7
전달되지 않은 인수는 정의되지 않은 상태로 제공됩니다. null에 대해 엄격한 동등성을 가진 테스트는 실패합니다. 정의되지 않은 엄격한 평등을 사용해야합니다.
Juan Mendes

19
기억 argument2 || 'blah';경우 'ㅋ'가 발생합니다 argument2입니다 false,이 정의되어 있지 단순히 경우 (!). 경우 argument2부울이며, 함수가 전달됩니다 false그것을 위해, 그 라인에도 불구하고 'ㅋ'를 반환합니다 argument2제대로 정의되고 .
Sandy Gifford

9
@SandyGifford : 같은 문제가있는 경우 argument2이다 0, ''또는 null.
rvighne

@rvighne 매우 사실입니다. 객체와 캐스팅에 대한 Javascript의 고유 한 해석은 한 번에 최고와 최악의 부분입니다.
Sandy Gifford

답변:


274

인수가 함수에 전달되었는지 확인하는 방법에는 여러 가지가 있습니다. (원래) 질문에서 언급 한 두 가지 외에도 연산자를 확인 arguments.length하거나 사용하여 ||기본값을 제공하는 경우 undefinedvia 를 통해 argument2 === undefined또는 typeof argument2 === 'undefined'편집증이 있는지에 대한 인수를 명시 적으로 확인할 수 있습니다 (주석 참조).

은 Using ||모든 멋진 아이가 그것을 할 - - 운영자 것은 표준 관행이되었습니다하지만 조심 : 기본 값은 인수 평가되는 경우에 트리거됩니다 false, 실제로 될 수있는 수단 undefined, null, false, 0, ''(나에 대해 아무것도 Boolean(...)반환false ).

따라서 어떤 검사를 언제 사용해야하는지에 대한 질문은 모두 약간 다른 결과를 산출하기 때문입니다.

확인 중 arguments.length 는 '가장 올바른'행동을 보여 주지만, 둘 이상의 선택적인 인수가있는 경우에는 실행되지 않을 수 있습니다.

다음 테스트 undefined는 '최고'입니다. 함수가 명시 적으로 호출 된 경우에만 '실패'합니다undefined 값 . 인수를 생략하는 것과 같은 방식으로 처리해야합니다.

의 사용 || 운영자는 유효한 인수가 제공되는 경우에도 기본 값의 사용을 트리거 할 수 있습니다. 반면에, 실제로는 그 동작이 필요할 수 있습니다.

요약 : 당신이하고있는 일을 알고있는 경우에만 사용하십시오!

내 의견으로는, ||선택 인수가 둘 이상 있고 명명 된 매개 변수에 대한 해결 방법으로 객체 리터럴을 전달하지 않으려는 경우 사용하는 방법도 있습니다.

arguments.lengthswitch 문 레이블을 통해 기본값을 사용하는 또 다른 좋은 방법 이 가능합니다.

function test(requiredArg, optionalArg1, optionalArg2, optionalArg3) {
    switch(arguments.length) {
        case 1: optionalArg1 = 'default1';
        case 2: optionalArg2 = 'default2';
        case 3: optionalArg3 = 'default3';
        case 4: break;
        default: throw new Error('illegal argument count')
    }
    // do stuff
}

이것은 프로그래머의 의도가 (시각적으로) 명확하지 않으며 '마법의 숫자'를 사용한다는 단점이 있습니다. 따라서 오류 가능성이 높습니다.


42
누군가 "undefined"를 정의한 경우 typeof argument2 === "undefined"를 실제로 확인해야합니다.
JW.

133
나는 통지를 추가 할 것입니다-그러나 아픈 나쁜 놈들은 어떻게 그런 일을합니까?
Christoph

12
undefined는 전역 공간의 변수입니다. 전역 범위의 변수를 로컬 범위의 변수보다 조회하는 것이 느립니다. 그러나 가장 빠른 사용하는 것입니다 대해서 typeof X === "정의되지 않은"
일부

5
흥미 롭군 반면, 비교 === undefined는 문자열 비교보다 빠를 수 있습니다. 내 테스트는 당신이 맞아 있음을 시사한다 생각 :의 X === 정의되지 않은 필요 ~ 1.5 시간 대해서 typeof X === '정의되지 않은'
크리스토프

4
@ 크리스토프 : 귀하의 의견을 읽은 후 주위에 물었습니다. 거대한 문자열을 비교하는 데 작은 문자열보다 시간이 오래 걸리기 때문에 포인터 비교를 통해 문자열 비교가 확실하지 않다는 것을 증명할 수있었습니다. 그러나 두 개의 거대한 문자열을 연결하면 연결로 구성된 경우에만 속도가 느리지 만 두 번째 문자열이 첫 번째 문자열로 할당 된 경우에는 빠릅니다. 그래서 그것은 아마도 문자 테스트에 의해 문자 테스트 다음에 포인터 테스트에 의해 작동 그래서 그래, 난 쓰레기로 가득했습니다 :) 나를 깨달아 주셔서 감사합니다 ...
Juan Mendes

17

jQuery를 사용하는 경우 (특히 복잡한 상황에서) 좋은 옵션 중 하나는 jQuery의 extend 메소드 를 사용 하는 것 입니다.

function foo(options) {

    default_options = {
        timeout : 1000,
        callback : function(){},
        some_number : 50,
        some_text : "hello world"
    };

    options = $.extend({}, default_options, options);
}

함수를 호출하면 다음과 같이됩니다.

foo({timeout : 500});

옵션 변수는 다음과 같습니다.

{
    timeout : 500,
    callback : function(){},
    some_number : 50,
    some_text : "hello world"
};

15

이것은 테스트를 찾는 몇 가지 경우 중 하나입니다.

if(! argument2) {  

}

꽤 잘 작동하고 구문 적으로 올바른 의미를 전달합니다.

(동시 제한으로 argument2인해 다른 의미가 있는 합법적 인 null 값을 허용하지 않지만 실제로는 혼란 스럽습니다.)

편집하다:

이것은 느슨한 언어와 강력한 언어 사이의 문체 차이의 좋은 예입니다. 자바 스크립트가 스페이드로 제공하는 스타일 옵션.

저의 개인적 선호는 (다른 선호에 대한 비판이없는) 미니멀리즘입니다. 일관성 있고 간결한 코드의 말이 적을수록 다른 사람이 내 의미를 올바르게 유추 할 수있는 사람이 줄어 듭니다.

이 환경 설정의 한 가지 의미는 여러 가지 유형 의존성 테스트를 쌓고 싶지 않다는 것입니다. 대신, 코드가 의미하는 것처럼 보이도록 코드를 만들려고합니다. 실제로 테스트해야 할 항목 만 테스트하십시오.

다른 사람들의 코드에서 찾은 악화 중 하나는 더 큰 맥락에서 실제로 테스트중인 사례에 도달 할 것으로 기대하는지 여부를 파악해야합니다. 또는 그들이 가능한 모든 것을 테스트하려고 할 때, 문맥을 완전히 예상하지 못할 가능성이 있습니다. 즉, 자신있게 무언가를 리팩토링하거나 수정하기 전에 양방향으로 철저하게 추적해야합니다. 나는 그들이 필요로하는 상황 (그리고 일반적으로 나에게는 분명하지 않은)을 예견했기 때문에 다양한 시험을 시행 할 가능성이 높다고 생각한다.

(이 사람들이 동적 언어를 사용하는 방식에 심각한 단점이 있다고 생각합니다. 너무 많은 사람들이 모든 정적 테스트를 포기하고 결국 가짜를 원하지 않습니다.)

포괄적 인 ActionScript 3 코드와 우아한 자바 스크립트 코드를 비교할 때 가장 눈에 띄게 나타났습니다. AS3은 js의 3 ~ 4 배가 될 수 있으며, 결정된 코딩 결정의 수 (3-4X) 때문에 신뢰성이 적어도 나아지지 않습니다.

당신이 말했듯이, Shog9, YMMV. :디


1
if (! argument2) argument2 = 'default'는 argument2 = argument2와 같습니다. || '
Christoph

5
그리고 나는 그것이 더 장황하고 산만하다는 것을 안다. 하지만 개인적인 취향입니다.
dkretz 2018 년

4
@le dorfier : 또한 빈 문자열, 0 및 부울 false를 사용할 수 없습니다.
Shog9

@le dorfier : 미학을 넘어 서면 한 가지 중요한 차이점이 있습니다. 후자는 효과적으로 두 번째 실행 경로를 만들어 부주의 한 관리자가 기본값을 할당하는 것 이상으로 행동을 추가하도록 유혹 할 수 있습니다. 물론 YMMV.
Shog9

3
parameter2가 부울 === false이면 어떻게됩니까? 또는 함수 {return false;}?
fresko

7

중요한 차이점이 있습니다. 몇 가지 테스트 사례를 설정해 보겠습니다.

var unused; // value will be undefined
Test("test1", "some value");
Test("test2");
Test("test3", unused);
Test("test4", null);
Test("test5", 0);
Test("test6", "");

첫 번째 방법은 두 번째 테스트에서만 기본값을 사용합니다. 두 번째 방법은 JS 변환되므로 (첫번째 제외한 모든 기본 것 undefined, null, 0, 및 ""부울로 false는 톰의 방법을 사용한다면. 그리고, 4 번째 테스트가 기본값을 사용합니다!

어떤 방법을 선택하는지는 의도 한 행동에 따라 다릅니다. undefined에 허용되는 값 이외의 값이 있으면 argument2첫 번째 변형을 원할 것입니다. 0이 아닌 null이 아닌 비어 있지 않은 값이 필요한 경우 두 번째 방법이 이상적입니다. 실제로 이러한 넓은 범위의 값을 고려에서 신속하게 제거하는 데 종종 사용됩니다.


7
url = url === undefined ? location.href : url;

베어 본이 대답합니다. 약간의 설명은 아프지 않을 것입니다.
Paul Rooney

URL이 정의되지 않은 경우 (누락 된 경우) url 변수를 location.href (현재 웹 페이지)로 설정하고, 그렇지 않으면 url 변수를 정의 된 url로 설정하십시오.
rmooney

5

ES6 (ES2015)에서는 기본 매개 변수를 사용할 수 있습니다

function Test(arg1 = 'Hello', arg2 = 'World!'){
  alert(arg1 + ' ' +arg2);
}

Test('Hello', 'World!'); // Hello World!
Test('Hello'); // Hello World!
Test(); // Hello World!


이 답변은 정말 흥미롭고 op에 유용 할 수 있습니다. 정말하지 않지만 응답 질문
ULYSSE BN


내 요점은 당신이 JavaScript 함수에 인수가 보내지지 않았는지 결정하는 가장 좋은 방법에 대답 하지 않는다는 것 입니다. 그러나 기본 인수를 사용하여 질문에 대답 할 수 있습니다. 예를 들어 인수의 이름을 지정 "default value"하고 값이 실제로 있는지 확인하십시오 "default value".
Ulysse BN

4

죄송합니다, 아직 댓글을 달 수 없습니다. Tom의 답변에 대답하려면 ... javascript (undefined! = null) == false 실제로 해당 함수가 "null"과 함께 작동하지 않으면 "undefined"를 사용해야합니다.


1
그리고 Tom은 틀린 답에 대해 두 개의 공감대를 얻었습니다.이 커뮤니티 시스템이 얼마나 잘 작동하는지 아는 것이 좋습니다.)
Christoph

3

!!연산자를 사용하지 않습니까? 변수 앞에 배치이 연산자는, (내가 잘 이해 한 경우) 부울로 설정, 그래서 !!undefined하고 !!null(심지어 및 !!NaN반환 매우 흥미로운 일이 될 수있는) false.

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

function foo(bar){
    console.log(!!bar);
}

foo("hey") //=> will log true

foo() //=> will log false

부울 true, 0 및 빈 문자열에는 작동하지 않습니다. 예를 들어, foo (0); false를 기록하지만 foo (1)는 true를 기록합니다
rosell.dk

2

선택적 속성의 객체로 함수를 호출하여 인수 감지에 접근하는 것이 편리 할 수 ​​있습니다.

function foo(options) {
    var config = { // defaults
        list: 'string value',
        of: [a, b, c],
        optional: {x: y},
        objects: function(param){
           // do stuff here
        }
    }; 
    if(options !== undefined){
        for (i in config) {
            if (config.hasOwnProperty(i)){
                if (options[i] !== undefined) { config[i] = options[i]; }
            }
        }
    }
}

2

잘 찾을 수있는 등 까다로운 방법은 매개 변수가 함수 나하지로 전달되는지 여부 . 아래 예제를 살펴보십시오.

this.setCurrent = function(value) {
  this.current = value || 0;
};

이것은 필요한 값이 value존재하지 않거나 통과하면 0으로 설정 한다는 것을 의미합니다 .

꽤 멋진 응!


1
"경우 실제로 수단 value에 상당 false, 0으로 설정" 이것은 미묘하지만 매우 중요한 차이점입니다.
찰스 우드

@CharlesWood 값되지 통과 / 현재 수단은 거짓
모하메드 Zameer

1
기능에 대한 요구 사항에 맞는 경우에는 물론입니다. 그러나 경우, 예를 들어, 매개 변수는 다음 부울입니다 truefalse유효한 값이며, 당신은 매개 변수 (함수가 하나 개 이상의 매개 변수가 특히) 전혀 전달되지 않는 경우에 대한 세 번째 동작을 할 수 있습니다.
찰스 우드

1
그리고 나는 이것이 컴퓨터 과학에서 큰 논쟁이며, 결국 의견의 문제가 될 수 있음을 인정해야합니다. D
Charles Wood

@CharlesWood 파티에 늦어서 죄송합니다. 편집 옵션을 사용하여 답변 자체에 추가하는 것이 좋습니다.
Mohammed Zameer

1

때로는 getter 및 setter로 함수를 사용하는 경우 유형을 확인하고 싶을 수도 있습니다. 다음 코드는 ES6입니다 (EcmaScript 5 이상에서는 실행되지 않음).

class PrivateTest {
    constructor(aNumber) {
        let _aNumber = aNumber;

        //Privileged setter/getter with access to private _number:
        this.aNumber = function(value) {
            if (value !== undefined && (typeof value === typeof _aNumber)) {
                _aNumber = value;
            }
            else {
                return _aNumber;
            }
        }
    }
}

0
function example(arg) {
  var argumentID = '0'; //1,2,3,4...whatever
  if (argumentID in arguments === false) {
    console.log(`the argument with id ${argumentID} was not passed to the function`);
  }
}

배열은에서 상속 받기 때문입니다 Object.prototype. 세상을 더 좋게 만들려면 ⇑을 고려하십시오.


-1

fnCalledFunction (Param1, Param2, window.YourOptionalParameter)

위의 함수가 많은 곳에서 호출되고 모든 곳에서 처음 두 개의 매개 변수가 전달되었지만 세 번째 매개 변수는 확실하지 않으면 window를 사용할 수 있습니다.

window.param3은 호출자 메소드에서 정의되지 않은 경우 처리합니다.

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