논리연산자는 무조건 true나 false로 평가되지 않을 수 있다.
그 전에는 나도 몰랐는데 이제와서 뒤통수 얼얼..
논리합(||)과 논리곱(&&) 연산자 표현식은 언제나 2개의 피연산자 중 어느 한쪽으로 평가된다.
'a' && 'b' //"b"
여기서 b가 출력된 이유는?
논리복(&&)은 두 피연산자가 모두 true로 평가될 때만 true를 반환한다.
'a'는 Truthy 갑이므로 true로 평가됐지만 다음 피연산자까지 Truthy값을 가져야만 true를 반환할 수 있으며 이 외 falsy값을 넣을 경우에는 false를 반환한다.
그러므로 뒤에 있는 피연산자 'b'가 논리곱 연산자 표현식의 평가 결과를 결정하는 것이다.
이 때, 논리곱 연산자는 연산의 결과를 true로 만들어준 피연산자인 'b'를 반환한다.
논리곱(||) 또한 true를 반환하는 조건만 다를 뿐이지 작동은 논리곱과 같다.
'a' || 'b' //"a"
논리곱은 두 피연산자 중에서 하나만 참이어도 true를 반환한다.
그러므로 좌항->우항으로 평가하는 논리 연산자의 경우 'a'를 평가했을 때 true임으로 뒤의 값은 참이든 거짓이든 상관이 없다.
어쨌든 'a'로 true인게 결정되었으니 더 평가를 할 필요가 없는 것이다.
그렇기에 'a'를 반환한 것.
이렇게 논리 연산의 결과를 결정하는 피연산자를 타입 변환하지 않고 반환하는 것을 단축평가(short-circuit evaluation)이라고 한다.
단축평가는 앞에서 말헀듯 결과가 확정되었을 때 나머지 평가 과정을 생략한다.
true || 아무거나 | true |
false || 아무거나 | 아무거나 |
true && 아무거나 | 아무거나 |
false && 아무거나 | false |
결과적으로 앞 피연산자부터 평가 결과가 확정되는 것은 논리합의 앞 피연산자가 true일 때나 논리곱의 앞 피연산자가 false 값을 가질 때이다.
이걸 보다보면 if문과 비슷하다.
If문은 참이 될 때만 작동하니, 논리값 연산자에서 참이 될 때 반환할 값을 넣기만 하면 된다.
var done = true;
var message = '';
//일반 if문
if(done) message = '완료';
//단축 평가로 바꾸기
message = done &&'완료';
console.log(message); //완료
거짓으로 평가되는 값일 때 반환하고 싶다면 논리합
var done = false;
var message ='';
//일반 if문
if(done) message = '미완료';
//단축평가로 바꾸기
message = done || '미완료';
console.log(message);
그럼 앞 피연산자가 거짓으로 평가되므로 자연스럽게 뒤에서 참으로 평가될 수 있는 메세지가 뜰 수 있다.
참고로 if문에 else까지 쓰려면 삼항 조건 연산자로 써도 된다.
var done = true;
var message = '';
//if else문
if(done) message = '완료';
else message = '미완료';
console.log(message);
//삼항 조건 연산자
message = done ? '완료' : '미완료';
console.log(message); //완료
솔직히 큰 차이는 못 느끼겠다
나중에 가서 코드가 조금 길어진다 싶으면 쓸 것 같기도..
코린이라 잘 모른다ㅎ
객체는 아직 배우지 않았지만, 단축평가의 유용한 패턴이라길래 미리 적어놓음
객체가 가리키기를 기대하는 변수가 null 또는 Undefined가 아닌지 확인하고 프로퍼티 참조
객체는 가리키기를 기대하는 변수의 값이 Null 또는 undefined인 경우 타입에러(TypeError)가 발생
이를 방지하기 위한 단축평가
var elem = null;
var value = elem && elem.value;
null값이나 undefined 값이 들어올 때 바로 출력시켜버리면 에러가 뜨니까 따로 변수를 설정하여 해당 값이 참이면 elem.value를 반환하게 하고 거짓일 경우에는 elem으로 평가되도록 만들어 반환시킨다.
함수 매개변수에 기본값을 설정할 때
함수를 호출하고 인수를 전달하지 않으면 undefined가 할당되는데, 이를 통한 에러를 방지
function getStringLength(str){
str = str || '';
return str.length;
}
getStringLength(); //0
getStringLength('hi'); //2
str이 참으로 평가될 경우에는 그대로 str의 값을 가지고, 거짓으로 평가될 때는 빈 문자열을 가지게 만든다.
이러면 따로 에러가 뜨지 않고 함수에 아무것도 넣지 않았을 때 기본 값으로 빈 문자열이 들어가므로 해당 문자열의 길이는 0으로 출력된다.
옵셔널 체이닝 연산자(optional chaining)
옵셔널 체이닝(optional chaining) 연산자 ?.는 좌항의 피연산자가 null 또는 undefined인 경우 undefined를 반환하고 그렇지 않은 경우는 우항의 프로퍼티 참조를 이어간다.
var elem = null;
var value = elem?.value;
console.log(value); //undefined
결국 모양만 다르지 논리곱(&&)을 사용한 단축 평가처럼 작동한다.
var elem = null;
var value = elem && elem.value;
console.log(value);
차이는 뭘까?
얘네가 받는 Falsy 값에 따라 다르다.
논리연산자 &&는 Falsy값(false, undefined, null, 0, -0, NaN,'')이면 이 피연산자 그대로 반환한다.
0이나 ''같은 경우도 반환시켜버린다는게 문제.
우리는 null 값과 undefined 값을 가지는 경우에만 우항의 값을 반환시키도록 하고 싶다.
이 때 옵셔널 체이닝 연산자는 Falsy값 중에서도 null과 undefined만 받고 아닌 경우에는 모두 우항의 프로퍼티 참조를 이어간다는 차이점이 있다.
null 병합 연산자(nullish coalescing)
null 병합 연산자 ??는 좌항의 피연산자가 null 또는 undefined인 경우 우항의 피연산자를 반환하고, 그렇지 않으면 좌항의 피연산자를 반환한다.
var a = null ?? 'default string'
console.log(a); //"default string"
옵셔널 체이닝 연산자와 비슷하지만, null 병합 연산자는 변수에 기본값을 설정할 때 더 유용하다.
얘도 논리합(||)으로 쓰다보면 0과 ''같은 경우가 기본값으로서 유효하다면 예기치 않은 동작이 발생할 가능성이 있기 때문에 null 병합 연산자는 이를 차단했다.
var a = '' ?? 'default string';
console.log(a); //""
그러니 ''와 0의 경우도 제외해서 오로지 null과 undefined인 경우에만 우항의 기본값을 가지도록 만든 것이다.
'Web development > Modern JavaScript Deep Dive' 카테고리의 다른 글
모던 자바스크립트 Deep Dive(변수 선언의 실행 시점과 변수 호이스팅) (0) | 2023.03.18 |
---|---|
모던 자바스크립트 Deep Dive(변수 선언) (0) | 2023.03.18 |
모던 자바스크립트 Deep Dive(암묵적 타입 변환, 명시적 타입 변환) (0) | 2023.03.15 |
모던 자바스크립트 Deep Dive(변수, 식별자) (0) | 2023.03.14 |
모던 자바스크립트 Deep Dive(제어문 - 블록문, 조건문, 반복문) (0) | 2023.03.13 |