관련 지식
#javascript #logical-operators

이번엔 분명히 알고 있는 논리연산에서 모르는 내용을 설명 드리겠습니다. 이전에 봤던 소스에서 아! 그래서 쓴거구나 하실수도 있겠네요.

예를들어 자바의 if 조건에는 오직 true/false 만 들어갈 수 있습니다. 때문에 변수는 true/false로 정할수 있는 조건식이 필요합니다. 그러나 자바스크립트에서는 true/false 뿐 아니라 객체 자체도 조건이 될 수 있습니다.

거짓으로 변환할 수 있는 값)

  • null;
  • NaN;
  • 0;
  • empty string (“”);
  • undefined.

위의 값들은 조건식으로 사용시 false가 되는 경우로 반드시 아셔야 합니다. 예제를 보겠습니다.

  1. var elem = null;
  2. if(elem) { //false
  3. console.log('ok ' + elem);
  4. }
  5. elem = "문자열";
  6. if(elem) { //true
  7. console.log('ok ' + elem);
  8. }
  9. elem = { a : function() {} };
  10. if(elem) { //true
  11. console.log('ok ' + elem);
  12. }

elem 변수에 true/false와 관련이 없어보이는 문자와 객체가 저장 되었을때도 조건식이 true가 되었습니다. 객체가 있으면 true로 판단하기 때문입니다. 하지만 무심결에 아래와 같이 사용하면 원치 않는 값을 볼 수 있습니다.

  1. elem = 3;
  2. if(elem) { //true
  3. console.log('ok ' + elem);
  4. }
  5. elem = 0;
  6. if(elem) { //false
  7. console.log('ok ' + elem);
  8. }

자바스크립트에서 객체의 유무로 if 설정을 하는것은 매우 편하지만 그것에 익숙해질 경우 숫자 0도 true로 생각할수 있으므로 주의하셔야 합니다. 숫자0은 값이 있는것이지만 그것은 false 입니다.

혹시 지금까지 소스에서 아래와 같은 조건식을 본적이 있으신가요? 당장 바꾸세요.

  1. var dom = document.getElementById("asdasdfasdf");
  2. //수정 전
  3. if(dom != undefined && dom != null && dom != "undefined" && dom != "null") {
  4. console.log('ok ' + elem);
  5. }
  6. //수정 후
  7. if(dom) {
  8. console.log('ok ' + elem);
  9. }

undefined와 null은 키워드입니다. 혹시 문자열로 넘어오는 경우를 봤다면 비교식을 추가하는게 아니라 문자열로 넘겨주는 쪽을 수정해야 합니다.

Logical NOT (!)

조건식은 깔끔할수록 좋습니다. 복잡한 조건식은 이해하기 어렵기 때문이죠. 그러나 어떤 경우엔 너무 간단한 조건식이라 무심코 작성하는 경우가 있습니다. 아래처럼요. 아래 함수는 ‘0보다 큰 수 a와 b를 합한 값을 리턴하는 함수’ 를 작성한 예 입니다.

  1. //0보다 큰 수 a와 b를 합한 값을 리턴하는 함수
  2. function sum(a, b) {
  3. if(a) {
  4. if(b) {
  5. return a + b;
  6. }
  7. else {
  8. return -2; //b값이 없을때 -2 리턴
  9. }
  10. }
  11. else {
  12. return -1; //a값이 없을때 -1 리턴
  13. }
  14. }
  15. console.log(sum(10)); //-2
  16. console.log(sum(null, 20)); //-1
  17. console.log(sum(10, 20)); //30

a 와 b 변수의 값이 없을때는 음수가 리턴되도록 에러처리 되어있습니다. 이 코드가 최선일까요? 이보다 더 쉽게 만들수 없을까요? 저라면 이렇게 만들것입니다.

  1. //a와 b를 합한 값을 리턴하는 함수
  2. function sum(a, b) {
  3. if(!a) {
  4. return -1; //a값이 없을때 -1 리턴
  5. }
  6. if(!b) {
  7. return -2; //b값이 없을때 -2 리턴
  8. }
  9. return a + b;
  10. }

중괄호 {} 의 중첩이 없어졌습니다. 이러한 코드 스타일은 추가적인 조건을 넣을때도 편리하고 전체 플로우를 이해하기 쉽게 만들어 줍니다. ! 하나를 이용하는 것만으로 코드 스타일을 바꿀수 있기 때문에 지금까지 잘 안써봤다면 이제부턴 써보세요.

Logical AND (&&)

누구나가 많이 쓰는 && 논리식 입니다. 그런데 이 논리식엔 재밌는 특징이 있어서 이것을 이용한 재밌는 코딩을 할 수 있습니다. 바로 아래와 같은 특징입니다.

  1. a1 = true && true // t && t returns true
  2. a2 = true && false // t && f returns false
  3. a3 = false && true // f && t returns false
  4. a4 = false && (3 == 4) // f && f returns false
  5. a5 = 'Cat' && 'Dog' // t && t returns "Dog"
  6. a6 = false && 'Cat' // f && t returns false
  7. a7 = 'Cat' && false // t && f returns false
  8. a8 = '' && false // f && f returns ""
  9. a9 = false && '' // f && f returns false

1~4까지는 자바와도 별 다를게 없어 보이지만 5번째 부터는 자바에선 상상도 못한 결과가 나옵니다. 간단하게 정리하면 논리식이 ‘참 ‘이라면 우측 값을, ‘거짓’이라면 거짓인 값을 return 한다는것! true/false 로만 리턴하는 자바와는 많이 다르죠?

  1. var val1 = "이미";
  2. var val2;

위와 같이 변수가 있을때 val1 의 값이 존재하면 val2 에 ‘있음’ 이라고 저장하고 val1의 값이 존재하지 않을 경우 val1과 같은 상태로 세팅하고 싶습니다.(null일땐 null로, 빈문자열일땐 빈 문자열로) 어떻게 할까요?

  1. var val1 = "이미";
  2. var val2;
  3. // if(val1) {
  4. // val2 = "있음";
  5. // }
  6. // else {
  7. // val2 = val1;
  8. // }
  9. // val2 = val1 ? "있음" : val1;
  10. val2 = val1 && "있음";
  11. console.log(val2);

‘있음’ 이라는 문자열 자체가 ‘true’ 를 만족하기 때문에 val1이 참일 경우(값이 존재하는 경우) ‘있음’ 이 return 됩니다. 그러나 val1 값이 없을 경우 그 값이 그대로 return 됩니다. 삼항연산을 쓸 수도 있지만 && 논리식을 사용하는 것이 더 간결합니다.

Logical OR (||)

논리식 || 도 재밌는 코딩을 할 수가 있습니다. || 논리식은 ‘참’이 되는 값을 return 하거나 논리식이 ‘false’ 이면 우측값을 리턴합니다.

  1. o1 = true || true // t || t returns true
  2. o2 = false || true // f || t returns true
  3. o3 = true || false // t || f returns true
  4. o4 = false || (3 == 4) // f || f returns false
  5. o5 = 'Cat' || 'Dog' // t || t returns "Cat"
  6. o6 = false || 'Cat' // f || t returns "Cat"
  7. o7 = 'Cat' || false // t || f returns "Cat"
  8. o8 = '' || false // f || f returns false
  9. o9 = false || '' // f || f returns ""

아래와 같은 변수가 있을때 val1의 값이 있으면 val1 값을 val3으로, val1의 값이 없을땐 val2의 값을 val3으로 넣으려면 어떻게 할까요?

  1. var val1 = "있음";
  2. var val2 = "없음";
  3. var val3;

역시 삼항연산을 쓸수도 있지만 아래와 같이 가능합니다.

  1. var val1 = "있음";
  2. var val2 = "없음";
  3. var val3;
  4. // if(val1) {
  5. // val3 = val1;
  6. // }
  7. // else {
  8. // val3 = val2;
  9. // }
  10. // val3 = val1 ? val1 : val2;
  11. val3 = val1 || val2;
  12. console.log(val3);

흔히 값 초기화에서 사용 하는 방식입니다.

  1. function setOption(o) {
  2. var option = {};
  3. option.title = o.title || '제목없음';
  4. console.log(option);
  5. }
  6. setOption({title : ''});

Double NOT (!!)

자바스크립트의 &&|| 이 재밌는것은 리턴값이 true/false 로 고정되어있지 않다는 것입니다. 그래서 그 특징을 이용한 트릭 코딩이 가능한데 반드시 true/false로 필요한 경우도 있을 것입니다.

  1. function hasOption(op) {
  2. //return op;
  3. }
  4. console.log(hasOption(null)); //false로
  5. console.log(hasOption({})); //true로

hasOption() 함수의 본문을 어떻게 작성해야 할까요?

  1. function hasOption(op) {
  2. return !!op;
  3. }
  4. console.log(hasOption(null)); //false로
  5. console.log(hasOption({})); //true로

객체에 ! 한개를 붙이면 객체의 상태와 반대로 true/false가 정해질 것입니다. 한개 더 붙이면 원래 객체의 상태를 true/false로 표현하게 되죠. 앞으로 !! 을 소스에서 보게 된다면 ‘아! 객체 상태를 boolean으로 변환하려는구나’ 생각하시면 됩니다.

정리

Logical ANDLogical OR
논리식이 참일때우측 값 리턴참인 값 리턴
논리식이 거짓일때거짓인 값 리턴우측 값 리턴
Logical NOTDouble NOT
논리식이 참일때false 리턴true 리턴
논리식이 거짓일때true 리턴false 리턴

참고 : MDN web docs - 논리 연산자