Skip to content

자바 스크립트에서 가치가 없는 값 확인하기

chchoing88 edited this page Apr 21, 2019 · 7 revisions

자바 스크립트에서 가치가 없는 값 확인하기

번역 : https://tomeraberba.ch/html/post/checking-for-the-absence-of-a-value-in-javascript.html

JavaScript를 처음 배우기 시작했을 때 개발자들은 가치가 없는지 끊임없이 확인했습니다.

console.log(value == null)
console.log(value === null)
console.log(value == undefined)
console.log(value === undefined)
console.log(value === undefined || value === null)
console.log(typeof value === 'undefined')
console.log(typeof value == 'undefined')
console.log(typeof value === 'undefined' || value === null)
console.log(typeof value === 'undefined' || value == null)
console.log(typeof value == 'undefined' || value == null)
console.log(typeof value == 'undefined' || value === null)
console.log(!value)

가치가 없는 값

이 표현들 중 어느 것이 올바른지를 이해하기 위해서는 자바 스크립트가 가치의 부족을 나타내는 두 가지 방법을 먼저 살펴 봐야합니다.

Undefined

undefined자바 스크립트의 기본 유형 중 하나입니다. 즉 typeof연산자를 사용하여 유형을 확인 하면 문자열을 반환합니다 'undefined'.

console.log(typeof undefined) // undefined

이것은 선언되었지만 할당되지 않은 변수의 기본값입니다.

var x
console.log(x) // undefined

선언되지 않은 객체 속성에 액세스하려고 할 때 반환되는 값입니다.

var obj = {}
console.log(obj.a) // undefined

반환하지 않는 함수의 기본 반환 값입니다.

function f() {}
console.log(f()) // undefined

void표현식을 평가 한 다음 반환하는 연산자 인 연산자에 의해 undefined를 반환됩니다

console.log(void 0) // undefined
console.log(void 'hello') // undefined
console.log(void(3 + 2)) // undefined
console.log(void(/* any expression */)) // undefined

그리고 마지막으로, 그것은 문자 그대로가 아닙니다. 그것은 전역 객체의 한 속성입니다, 항상 전역 범위에 존재 합니다. (객체 window브라우저의 속성).

Null ¶

null은 JavaScript 기본 유형이기도하지만 typeof연산자를 사용하여 유형을 검사 해도 예상 한 결과가 반환되지 않습니다.

console.log(typeof null) // object

W3Schools 에 따르면 이 동작을 JavaScript의 버그로 간주 할 수 있습니다. typeof null은 'null'을 반환해야 하지만 많은 코드가 이미 typeof null가 잘못된 'object' 반환 되었다는 가정하에 작성되었으므로 이전 코드가 손상되지 않도록 변경되지 않았습니다.

undefined, null 달리 어디서나 기본 값으로 표시되지 않습니다. 대신 대개 주어진 매개 변수에서 객체를 검색 할 수 없을 때잘못된 객체를 반환 할 것으로 예상되는 함수에 의해 반환됩니다.

예를 들어 HTML 문서에서 주어진 ID를 가진 요소가 발견되지 않으면 브라우저에서 다음을 document.getElementById반환 null합니다.

console.log(document.getElementById('some-id-which-no-element-has')) // null

undefined와 달리 null은 리터럴입니다. 일부 속성의 식별자가 아닙니다. 그것은 식별의 부족을 나타냅니다.

이러한 특성을 기반으로 undefined와 null이 모두 값의 부재라는 것을 말하는 것이 안전합니다. 따라서 값의 부재를 확인하기 위해 작성한 코드는 정의되지 않았으며 null을 모두 고려해야합니다.

평등 ¶

이제 우리는 undefined하고 null을 이해 있으며, 이 글의 시작 부분에있는 표현을 이해하기 위해서 == 그리고 === 그 차이점을 간략히 언급 할 필요가 있습니다.

엄격한 ¶

엄격한 평등은을 사용하여 호출 ===되며 비교적 간단합니다. 두 개의 값 a및 b유형이 다른 유형 인 경우 a === b반환 false합니다. 다만, 같은 타입과 내용이 일치하고있는 경우는 true 그 반대는 false를 돌려 주어집니다.

예 :

console.log(0 === 0) // true
console.log('hello!' === 'hello!') // true
console.log(null === null) // true
console.log(undefined === undefined) // true

console.log(0 === 5) // false
console.log(0 === '0') // false
console.log(0 === 'hello!') // false
console.log(null === undefined) // false

var obj = {}
console.log(obj === {}) // false (because objects are compared by reference)
console.log(obj === obj) // true (because reference to same object)

느슨한 ¶

== 사용하여 느슨한 품질을 호출하면 예기치 않은 결과가 종종 생성됩니다. 두 개의 값 a과 b같은 유형의 값 a === b이 반환 되면 반환됩니다. 그러나 서로 다른 유형 인 경우 JavaScript는 두 값을 동일한 유형으로 강제 변환 (즉 변환) 한 다음 두 유형을 엄격하게 동일하게 만듭니다. 이 두 번째 경우는 자바 스크립트 공동체에 의해 느슨한 동등성을 사용하는 것을 거의 권장하지 않습니다.

예 :

console.log(1 == 1) // true
console.log(1 == '1') // true (because the string was converted to a number)
console.log('1' == 1) // true (because the string was converted to a number)
console.log(0 == false) // true (because the boolean was converted to a number)
console.log(0 == null) // false (because absence of a value is never considered equal to a concrete value)
console.log({} == {}) // false (because objects are compared by reference)
console.log(0 == undefined) // false (because absence of a value is never considered equal to a concrete value)
console.log(null == undefined) // true (because both represent the absence of a value)
console.log(undefined == null) // true (because both represent the absence of a value)
console.log("hello!" == false) // false
console.log("" == false) // true (because the string was converted to a boolean and an empty string kind of represents falsity in the realm of strings I guess?)
console.log([] == false) // true (because the array was converted to a boolean and an empty array kind of represents falsity in the realm of array I guess?)

혼란 스럽다면 혼자만의 것이 아닙니다. 느슨한 평등을 완전히 이해하려면 이 피연산자 변환 테이블 과 진실성 및 잘못된 값에 대한 이 기사를 확인하십시오 . 또한 이 링크를 추천합니다.

모두 함께 가져옴 ¶

게시물 작업의 시작 부분에서 어떤 표현식을 확인해야 할 때입니다! 첫 번째 표현식을 살펴보고이를 평가할 체크리스트를 작성해 보겠습니다.

console.log(value == null)
  • 그것은 undefined에 true를 반환 하는가? 예, 때문에 대체 undefined에 대한 value수익률 undefined == null과 우리가 느슨한 평등 섹션에서 배운대로 undefined하고 null느슨하게 동일한 둘은 값이 없음을 나타 내기 때문이다.

  • 그것은 null에 true를 반환 하는가? 예, 왜냐하면 null을 value에 대입하면 null == null이 되고, 이는 명백히 true로 반환되기 때문이다.

  • 그것은 다른 모든 것에 false를 리턴합니까? 그렇습니다. 우리가 느슨한 평등 섹션에서 배운 바와 같이, null은 그 자체가 아닌 다른 것과 거의 동등하지 않으며 undefined은 왜냐하면 어떤 가치의 부재는 결코 구체적인 가치의 부재로 간주되지 않기 때문이다.

value == undefined 또한 같은 이유로 작용한다는것을 눈치 챘을 것이다. 그러나 value == null은 undefined 값은 일정하게 유지된다는 보장이 없기 때문에 더 안전합니다 . 자바 스크립트 버전이 나오기 전에 ES5 undefined는 단순히 전역 속성이기 때문에 재 할당 할 수 있으며 가장 최근 버전의 JavaScript undefined에서도 로컬 변수에 의해 가려질 수 있습니다. 이것 null은 문자 그대로이고 객관적으로 더 나은 선택이기 때문에 결코 일어날 수 없습니다 .

undefined의 예상 값을 반환한다는 보장이 있기 때문에 void 연산자를 대신 사용하여 이러한 정의되지 않은 문제를 피할 수 있습니다. 일반적으로 void 0은 짧고 빠르게 평가할 수 있기 때문에이 목적을 위해 void 연산자에 전달되는 식은 0입니다. 그러나 value == null 대신 value == void 0을 사용하는 것은 권장하지 않습니다. 그 이유는 다른 프로그래머 (대부분 void 연산자에 익숙하지 않습니다)를 혼동 할 수 있기 때문입니다. null은 void 0보다 2 문자 짧고 void 0 undefined가 반환되기 전에 0을 평가해야하기 때문에 null보다 약간 느릴 수 있습니다.

이러한 방법은 숨어있는 한 가지 문제를 제외하고 작동합니다. 우리의 모든 질문은 가치가 선언되었고 우리는 그것에 접근 할 수 있다는 사실을 알고 있다고 가정합니다. 그러나 값이 선언되지 않으면 코드가 ReferenceError를 던집니다. 변수가 선언되었는지 여부를 항상 알지 못하기 때문에 이것은 어리석은 것처럼 보일 수 있습니다. 불행히도 이것이 항상 그런 것은 아닙니다.

많은 JavaScript 라이브러리는 플랫폼에 무관심한 것을 목표로합니다. 그것들은 브라우저, 서버 또는 Node.js 모듈에서 실행될 수 있도록 설계되었습니다. Node.js에는 다른 모듈에서 사용할 메서드를 내보내는 데 사용할 수있는 전역 변수 모듈이 있지만 브라우저에서는이 변수가 선언되지 않습니다. 따라서 Node.js에서 module == null을 실행하면 false가 반환되지만 브라우저에서는 ReferenceError가 발생합니다! 이 문제를 처리하는 한 가지 방법은 try catch 블록을 사용하여 ReferenceError를 catch하고 Node.js에서 실행하지 않는 경우 실행을 다시 시작하는 것입니다.

try {
  value // expression statement will throw a ReferenceError if value is an undeclared variable
  console.log('value is declared') // will log if the previous statement did not throw an error
} catch (err) {
  console.log('value is undeclared') // will log if a ReferenceError was thrown
}

try 블록의 첫 번째 명령문 다음에 나오는 코드가 다른 이유로 오류를 던지면 값이 선언 되더라도 catch 블록이 실행됩니다. 이 문제는 throw 된 오류가 instanceof 연산자를 사용하여 특별히 ReferenceError인지 확인하여 방지 할 수 있습니다.

try {
  value
  console.log('value is declared')
  /* some potentially error-throwing code */
} catch (err) {
  if (err instanceof ReferenceError) {
    console.log('value is undeclared')
  } else {
    console.log('Some other error occurred')
  }
}

이 솔루션은 잠재적으로 오류 처리 코드가 ReferenceError를 던지지 않는 경우에만 작동하며, 이는 또한 해당 조건과 일치하기 때문이다. 나는 누군가가 일부러 이렇게 하는 이유를 생각할 수 없다. 이러한 상황은 선언된 변수의 이름을 잘못 표기하여 발생할 수 있다. 이러한 이유로 코드를 가능한 한 짧게 시도 캐치 블록에 보관하도록 해야 한다. 특정 변수 err instanceof ReferenceError && error.split(' ')'[0] === 'value'에 대한 ReferenceError 메시지 문자열을 확인하기 위해 조건을 변경할 수도 있지만, 코드에서 디버깅 및 수정해야 하는 변수 이름을 잘못 입력했다고 가정하기 때문에 권장하지 않는다.

변수가 선언되었는지 여부를 구체적으로 확인하려면 if 조건이 동일한 코드를 사용하는 것이 좋습니다. 그러나 선언되지 않은 변수를 결 측값으로 분류하고 undefined와 null로 럼프하고 싶다면 다행스럽게도 더 나은 해결책이 있습니다. typeof 연산자를 사용하여 선언되지 않은 변수의 유형을 확인하면 ReferenceError가 발생하지 않고 'undefined'라는 문자열이 반환됩니다. 이는 typeof 연산자를 사용하여 선언 된 변수의 유형을 undefined 값으로 검사 할 때 'undefined'문자열을 반환하기 때문에 편리합니다. 따라서 typeof value === 'undefined'표현식은 체크리스트의 첫 번째 항목을 체크합니다! 그러나 값이 null 인 경우에는 절을 고려하지 않으므로 or 절에 추가 검사를 추가해야합니다.

console.log(typeof value === 'undefined' || value === null)
  • 값이 선언되지 않은 경우에 true를 반환합니까? 예. typeof 연산자를 사용하여 선언되지 않은 변수의 유형을 확인하면 'undefined'라는 문자열이 반환되므로이를 대체하면 분명히 true를 반환하는 첫 번째 조건에서 'undefined'=== 'undefined'를 얻습니다. 첫 번째 조건은 true이므로 표현식이 단락되어 Value === null로 인해 발생했을 ReferenceError를 피할 수 있습니다. 단락에 의한 오류 발생 코드 실행 방지는 두 조건의 순서를 바꿀 수없는 이유를 보여줍니다.
  • 정의되지 않은 경우 true를 반환합니까? 예, 값에 대해 undefined를 사용하면 undefined == 'undefined'가 첫 번째 조건에서 생성되므로 'undefined'== 'undefined'로 단순화되고 분명히 true를 반환합니다.
  • 그것은 null에서 true를 반환합니까? 예. typeof null === 'undefined'로 인해 첫 번째 조건에서 값을 null로 대체하는 것이 실패하지만 'object'== 'undefined'로 단순화하여 두 번째 조건의 값을 null로 대체하면 null이됩니다. 분명히 사실을 반환합니다.
  • 그것은 다른 모든 것에 거짓을 반환합니까? 예, typeof 연산자를 사용하여 구체적인 값의 유형을 검사하면 'undefined'가 반환되지 않으므로 첫 번째 조건이 false를 반환하고 두 번째 조건을 구체 값으로 대체하면 null이 엄격하게 동일하므로 false를 반환합니다.

이 방법은 모든 상황에서 작동하지만 value == null보다 느립니다. 최적의 전략은 값이 선언되었는지 여부를 모르는 경우이 방법을 사용하고 이전 방법을 사용하는 것입니다. 실존 연산자를 JavaScript로 옮길 때 CoffeeScript가 취하는 접근 방식입니다.

게시물의 시작 부분에있는 표현 중 일부는 방금 평가 한 표현과 거의 동일하게 보입니다. 흥미롭게도 다음 네 표현식은 동일한 동작을 공유합니다.

console.log(typeof value === 'undefined' || value === null)
console.log(typeof value === 'undefined' || value == null)
console.log(typeof value == 'undefined' || value == null)
console.log(typeof value == 'undefined' || value === null)

그렇다면 우리는 왜 두 조건 모두에서 엄격한 평등을 가진 표현을 선택했을까요?

  • 엄격한 평등은 둘 다 피연산자 유형을 검사하기 때문에 느슨한 평등보다 느리지 않습니다.
  • 엄격한 동등성은 피연산자 타입 유형을 강제 변환하지 않고 즉시 false를 반환 할 수 있기 때문에 피연산자 유형이 다른 경우 느슨한 동등성보다 빠릅니다.
  • 느슨한 평등은 예기치 않은 결과를 낳기 때문에 가능하면 피해야합니다.

두 번째 불렛 포인트 따르면 value가 null과 동일한 유형이 아닐수도 있기 때문에 두 번째 조건에 대해서는 완전 항등(===) 사용을 해서 대한 강력한 인수를 사용하는게 이득이지만 첫 번째 조건에서는 typeof value와 'undefined'가 모두 string 유형으로 보장되므로 엄격한 평등 사용에 대한 결정은 첫 번째 및 세 번째 불렛 포인트에 의해 결정되어진다. 이렇게하면 위에서 첫 번째 표현이 최상의 선택입니다.

마지막으로 나머지 표현식을 게시물의 처음부터 평가 해 봅시다.

console.log(value === null) // doesn't account for undefined
console.log(value === undefined) // doesn't account for null
console.log(value === undefined || value === null) // works, but is simply a slower version of value == null and value == undefined
console.log(typeof value === 'undefined') // doesn't account for null
console.log(typeof value == 'undefined') // doesn't account for null
console.log(!value) // erroneously returns true for falsey values such as false, '', [], 0, etc.

개체 속성 ¶

객체 속성에 값이 없는지 확인하려면 속성 자체에 대해 추가 고려해야합니다. 다음 예제에서 value == null을 사용하여 각 객체의 키 속성에 값이 없는지 확인합니다.

var obj1 = {}
var obj2 = {
  key: undefined
}

console.log(obj1.key == null) // true
console.log(obj2.key == null) // true

키 특성이없는 오브젝트는 키 특성이 undefined 값으로 설정된 오브젝트와 동일한 결과를 생성합니다. 이것은 선언되지 않은 변수와 달리 선언되지 않은 속성의 값에 액세스하려고하면 항상 undefined를 반환하기 때문입니다. 즉, 선언되지 않은 속성을 결석 값으로 분류하고 정의되지 않은 값과 null로 덩어리로 묶으려는 경우 value == null은 좋은 해결책입니다. 그러나 특별히 속성이 선언되었는지 여부를 확인하려면 다른 방법을 사용해야합니다.

한 가지 방법은 in 연산자를 사용하는 것입니다.

var obj1 = {}
var obj2 = {
  key: undefined
}

console.log('key' in obj1) // false
console.log('key' in obj2) // true

속성 이름을 포함하는 string 또는 Symbol는 토큰이 아닌 in 연산자의 왼쪽에 사용해야합니다. 이것은 좋은 해결책처럼 보일지 모르지만 다음과 같은 경우를 고려하십시오.

var obj1 = {}
var obj2 = {
  constructor: undefined
}

console.log('constructor' in obj1) // true
console.log('constructor' in obj2) // true

아마도 당신이 옳다고 생각한 것이 아니겠습니까? obj1의 'constructor'표현식은 생성자 속성이 객체의 프로토 타입 체인에서 상속 되었기 때문에 true를 반환합니다. 즉, in 연산자는 상속 된 속성뿐 아니라 객체의 특정 속성을 모두 고려합니다.

다행히도 hasOwnProperty 메서드를 사용하여 개체의 특정 상속되지 않은 속성을 확인하는 방법이 있습니다. hasOwnProperty 메서드 자체는 Object 생성자 또는 개체 지향 조건의 클래스에서 상속받습니다.

var obj1 = {}
var obj2 = {
  constructor: undefined
}

console.log(obj1.hasOwnProperty('constructor')) // false
console.log(obj2.hasOwnProperty('constructor')) // true

in연산자 와 달리이 hasOwnProperty메서드는 string인수 만 취할 수 있습니다 . 이 hasOwnProperty방법 을 사용할 때 한 가지주의 할 점이 있습니다 . 다음과 같은 경우를 고려하십시오.

var obj = {
  hasOwnProperty: function () {
    return true
  }
}

console.log(obj.hasOwnProperty('wow')) // true

Object 생성자의 hasOwnProperty 메서드는 항상 true를 반환하는 메서드에 의해 객체 지향 용어에서 무시되거나 무시되었습니다. 속성에 액세스하면 항상 상속되지 않은 상속 된 속성이 우선적으로 선호되므로 신고되지 않은 속성의 이름에 대해 true가 반환됩니다. 다행히도이 문제를 해결할 방법이 있습니다. hasOwnProperty 메서드는 Object 생성자에서 직접 액세스하여 Function 생성자의 call 메서드를 사용하여 지정된 값으로 호출 할 수 있습니다. 호출 메소드는 this의 값을 첫 번째 인수로, 호출 된 함수에 대한 인수를 나머지 인수로 취합니다.

var obj = {
  hasOwnProperty: function () {
    return true
  }
}

console.log(Object.prototype.hasOwnProperty.call(obj, 'wow')) // false

이 방법을 두 번 이상 사용하는 자신을 찾으면 함수로 추출하는 것이 좋습니다.

function hasOwnProperty(obj, property) {
  return Object.prototype.hasOwnProperty.call(obj, property)
}

var obj = {
  hasOwnProperty: function () {
    return true
  }
}

console.log(hasOwnProperty(obj, 'wow')) // false

결론

여기에 최적의 표현이 있습니다.

변수가 선언되었는지 검사 :

try {
  value
  // value is declared
} catch (err) {
  if (err instanceof ReferenceError) {
    // value is undeclared
  } else {
    // some other error occurred
  }
}

객체가 확실히 shadowing hasOwnProperty 속성을 가지고 있지 않을 때 객체에 상속되지 않은 속성이 없는지 확인하기:

!obj.hasOwnProperty(key)

객체가 확실히 shadowing hasOwnProperty 속성을 가지고 있지 않을 때 객체에 상속되지 않은 속성이 있는지 검사하기:

obj.hasOwnProperty(key)

객체에 shadowing hasOwnProperty 속성이있을 때 객체에 상속되지 않은 속성이 없음을 확인합니다.

!Object.prototype.hasOwnProperty.call(obj, key)

객체가 shadowing hasOwnProperty속성을 가질 수있을 때 객체에 상속되지 않은 속성이 있는지 확인하기 :

Object.prototype.hasOwnProperty.call(obj, key)

객체에서 상속되거나 상속받지 않는 속성이 없는지 확인하기 :

!(key in obj)

객체에서 상속되거나 상속받지 않는 속성이 있는지 확인하기 :

key in obj

값이 선언되지 않은 변수 일 때 값이 없는지 확인하기 :

typeof value === 'undefined' || value === null

값이 선언되지 않은 변수 일 수있는 값의 존재 확인 ( De Morgan의 법칙을 사용하여 파생 됨 ) :

typeof value !== 'undefined' && value !== null

값이 확실하게 선언 될 때 값이 없는지 확인하기 :

value == null

값이 확실히 선언 될 때 값의 존재 확인 :

value != null

값이 명확히 선언되고 평등이 맞지 않을 때 값이 없는지 확인하기 :

value === null || value === void 0

값이 확실하게 선언되고 평등성을 피하려는 경우 (De Morgan의 법칙을 사용하여 파생 됨) 값의 존재를 확인합니다.

value !== null && value !== void 0

귀하의 필요에 맞게 이들 조합을 자유롭게 사용할 수 있습니다. 예를 들어 객체에 hasOwnProperty 속성의 섀도우가없는 객체가 undefined 또는 null과 같은 값이없는 상속되지 않은 속성이 있는지 확인하는 방법은 다음과 같습니다.

obj.hasOwnProperty(key) && obj[key] == null

읽어 주셔서 감사합니다!

Clone this wiki locally