sharingStorage

null과 undefined에 관한 고찰 본문

Front-End/Javascript

null과 undefined에 관한 고찰

Anstrengung 2024. 7. 10. 18:48

null과 undefined의 차이는 이미 알고있었지만 현재 진행하고있는 ASAP(최적의 회의시간 도출 서비스)에 대한 코드리뷰를 진행하던 중 팀원이 string타입인 시작시간을 undefined로 초기화하면 안되는 이유에 대해 물어보았을 때 설명하면서 내 지식에 공백이 있음을 느꼈다.

그래서 undefined와 null을 deep dive해보고 그 두개를 정확히 구분하지 않았을 때 발생하는 side Effect에 대해서 고민해보는 시간을 가져보려고 한다.

사건의 발단

 

null과 undefined를 한줄 요약하면

개발자가 의도적으로 "값이 없음"을 나타내기 위해 할당하는 값은 null

값이 초기화되지 않음을 자바스크립트 엔진이 표현한 값은 undefined이다.

 

MDN이 말하는 null과 undefined

일단 본인이 자명하다고(?) 생각하는 MDN에서는 null 값이 의도적으로 없음 을 나타낸다고 한다.

그리고 원시값이며, falsy한 값으로 다뤄진다.

MDN에서 말하는 null값

null is not an identifier for a property of the global object, like undefined can be.

Instead, null expresses a lack of identification, indicating that a variable points to no object. In APIs, null is often retrieved in a place where an object can be expected but no object is relevant.

 

null은 전역 객체의 property(속성)이 아닌데 undefined는 전역객체의 이다.

즉 undefined는 window.undefined로 접근할 수 있지만 null은 그렇지 못하다는 것이다.

null은 변수가 객체를 가리키지 않는다 라는 것을 명시적으로 나타내고 API에서는 객체가 존재하지 않으면 null을 반환하여 그 상황을 표현하는 것이 일반적이라고 말하고 있다.

 

 

MDN에서 undefined는 전역 property이며 undefined 원시값을 나타낸다고 한다.

A variable that has not been assigned a value is of type undefined.  In all non-legacy browsers, undefined is a non-configurable, non-writable property. Even when this is not the case, avoid overriding it.

 

할당되지 않은 변수의 타입은 undefined 타입이라고 말하고 있으며,

이는 모든 비 레거시 브라우저에서 non-configurable 하고 non-writable 한 property라고 한다. 이 부분은 ECMA script 공식문서 tc39를 참고해서 더 알아보았다.

일단 ECMA script 공식문서에서도 undefined값은 할당되지 않은 변수의 값, null값은 의도적으로 값이 없음을 나타내는 값이라고 한다.

 

ECMA script에서 말하는 undefined와 null

MDN에서 언급한 undefined의 non-configutable하고 non-writable한 값은 해당 문서에서도 찾아볼 수 있었다.

 

위 사진에 나온 3가지 attribute는 다음을 의미한다.

Writable : 값을 변경할 수 있는 가에 대한 boolean값.

// Writable 값이 true인 객체에 대한 예시

// 현재 페이지를 다른 URL로 리다이렉트
window.location = '<https://www.example.com>';

// 문서의 제목을 변경
document.title = '새로운 제목';

Enumerable : 열거 가능여부에 대한 boolean 값.

Configurable : 속성 자체에 속성을 변경할 수 있는지에 대한 boolean값. 이는 보호되고 있는 속성이며 한번 false인 값은 true로 변경할 수 없다.

 

null과 undefined 연산을 통해 보는 차이점

typeof null; // "object" 과거 구현상의 오류로 null의 typeof연산이 object로 나온다.
typeof undefined; // "undefined"
null === undefined; // false
null == undefined; // true
null === null; // true
null == null; // true
undefined == undefined //true
undefined === undefined //true
console.log(JSON.stringify({name: undefined})); // {}
console.log(JSON.stringify({name: null})); // {"life":null}

 

undefined가 return되는 코드의 예시

//변수의 값을 할당하지 않았을 때
let name;
console.log(name); //undefined

// 존재하지 않는 property에 접근했을 때
let person= {
	name:"jaehoon",
	gender:"man"
	}
console.log(person.age); //undefined

//반환 값이 없는 함수의 반환값
function foo(){
	return ;
}

console.log(foo()); //undefined

//built-in함수에서 값을 못찾았을 때
const array1 = [5, 4, 8, 2, 1];
const found = array1.find((element) => element > 10);

console.log(found);//undefined

 

null이 return되는 코드의 예시

  • DOM built-in function
document.getElementById("foo"); //null

 

성능

null이 V8엔진에서 아주 약간 성능이 더 좋다고 하지만 이는 undefined가 null보다 단지 string의 길이가 길기 때문에 발생하는 아주 미묘한 성능차이도 있고, 이정도 성능차이를 고려하는것은 무의미하다.

 

GC(Garbage Collector)에 대한 고려

몇몇 사람들은 null이 참조관계를 끊어서 도달할 수 없는 상태를 만들어 Garbage Collector를 작동하게 한다고 하지만 참조 관계를 끊어 도달할 수 없는 상태를 만드는 것은 undefined도 마찬가지이다.

javascript의 garbage collector는 도달할 수 없는 객체, 참조 카운팅 수가 0인 객체를 필요없는 객체로 간주하는 알고리즘을 기반으로 작동한다. 즉 참조를 끊어 garbage collector를 작동시키는 것은 null과 undefined 두 값 모두이다.

 

색다른 관점

여러 관점에서 여러 아티클을 보면서 공부하다가 MicroSoft Type가이드에서 아래와 같은 문구를 확인할 수 있다.

https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines#null-and-undefined

엄연히 null과 undefined는 쓰임이 다르다고 생각하는데 왜 이렇게 언급했을까?

가이드에서 해당 언급에 대한 이유까지 제시하진 않는다. (물론 해당 사안에 대해 누군가 질문했는데 TypeScript 컴파일러를 개발하는 가이드일뿐 TypeScript 일반 가이드는 아니라고 답변했다.

https://github.com/Microsoft/TypeScript/issues/8940

 

하지만 이런 관점에서 비롯된 js개발을 하는 동안 undefined만을 사용하자는 의견도 있다.

조금 풀어보자면 C, C++, JAVA 등의 언어는 없음 을 표현하는 값 또는 타입을 오직 하나씩 가지고 있는데 자바스크립트 만이 없음을 나타내는 값이 undefined와 null 두개이다.

이러한 상황에서 자바스크립트 엔진이 공인한 없음은 undefined이니 undefined를 통일해서 값이 없음을 나타내자는 의견이다. 개발자의 의도로 null을 사용한다면 falsy한 값을 사용할 때 null과 undefined를 모두 명시적으로 검사해야한다. 직관적으로 생각해봐도 여러번의 검사를 거쳐야한다는 것은 그만큼 휴먼 에러가 발생할 가능성도 높다.

예를들면 number의 값을 검사할 때 0인지, null인지, undefined 인지 모두를 검사해야하는 상황도 생길 수 있는 것이다.

 

두 번째 이유는 null의 typeof 연산의 값이 object라는 것이다.

이는 자바스크립트 상의 명백한 오류이지만 기존 코드에 미치는 영향이 너무 커서 수정하지 못하고 있는 legacy코드이다.

그래서 typeof 연산을 할 때 null의 사용은 각별히 유의해야한다는 문제가 있다.

 

결론

참신하고 색다른 여러 관점을 보았지만 결론만 말하자면 난 역시 없음을 표현하는 null과 undefined의 역할이 엄연히 다르고 구분해야한다고 생각한다.

 

위에서 언급한 색다른 관점에 대한 나의 생각은

falsy한 값에 대해 필요한 두번 이상의 검사 : null과 undefined의 쓰임과 역할이 다르니 당연한 과정이라고 생각하고 이로 인해 타입체크와 조건문으로 더 명확하게 코드를 작성할 수 있다.

typeof 연산에 대한 오류 : 분명 불편한 부분이 있긴 하지만 이를 피하기 위해 undefined만을 사용했을 때 발생하는 예외처리비용이 더 크다고 생각한다.

 

서버통신에서도 객체에서의 없음을 나타낼 땐 보편적으로 null값을 전달해주고 있고, 이 부분에서 undefined를 사용한다면 "서버통신의 실패여부로 인한 undefined"와 "값이 없음" 사이에 혼란을 줄 수 있고, javascipt자체에서 undefined를 반환하는 경우와 null을 반환하고 있는 경우(DOM built-in 함수)를 구분지어둔 것을 포함해서 MDN, ECMA script 공식문서에서도 null과 undefined를 명확히 구분하고 있다.

결정적으로 null을 사용하면서 개발자가 확실하게 특정 변수가 왜 비어있는지 확인 가능하지만 undefined를 혼용하면 할당되었는지, 존재하지 않는 속성인지에 대한 디버깅 과정에서의 어려움이 분명 발생할 것이고 유지보수가 어려워질 수 있다는 점이 가장 큰 이유라고 생각한다. 

 

이런 여러 상황을 판단해보았을 때 공식문서의 가이드를 따르지 않을 때의 비용이 더 크기에 null과 undefined를 명확히 구분해서 사용해야한다고 생각한다.

 

참고링크

https://blog.shiren.dev/2021-10-05/

https://tc39.es/ecma262/#sec-null-value

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/null

https://github.com/Microsoft/TypeScript/issues/8940

https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines#null-and-undefined

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_management#reference-counting_garbage_collection

'Front-End > Javascript' 카테고리의 다른 글

JSON  (0) 2022.03.17
RxJS  (0) 2021.12.29
참조에 의한 객체 복사  (0) 2021.12.28
Comments