[JS] 조건처리/논리연산자/함수

PinkTopaz·2023년 4월 9일
0
post-thumbnail
post-custom-banner

32기 솝트 웹파트 자바스크립트 스터디 1주차에서 공부한 내용을 정리합니다. (출처 : 모던자바스크립트 튜토리얼 2.10,2.11,2.16,2.17)


if와 '?'를 사용한 조건 처리

불린형으로의 변환

if문에서는 괄호 안의 표현식을 평가하고 그 결과를 불린값으로 반환한다.

숫자 0, 빈 문자열"", null, undefined, NaN은 형변환 규칙에 따라 불린형으로 변환 시 모두 false가 된다.
이러한 값을 falsy한 값(거짓 같은 값)이라고 부르고, 이 외의 값은 불린형으로 변환 시 모두 true가 되므로 truthy한 값 (참 같은) 값이라고 부른다.

if (0) { // 0은 falsy로, 코드 블록이 절대 실행되지 않는다. 
  ...
}

if (1) { // 1은 truthy로, 코드 블록이 항상 실행된다. 
  ...
}

조건부 연산자 '?'

조건부 연산자는 피연산자가 3개로 삼항 연산자라고 부르기도 한다.
자바스크립트에서 피연산자를 3개나 받는 연산자는 삼항 연산자가 유일하다고 한다.

let result = condition ? value1 : value2;

// let myLevel= (score > 50) ? 2 : 1;

condition이 truthy라면, value1이, 그렇지 않다면 value2가 반환된다.
condition에 괄호가 있으나 없으나 큰 차이는 없지만, 코드의 가독성 향상을 위해 괄호를 사용할 것을 권장한다.

다중 ?

물음표 연산자 ?를 여러개 연결해서 if~else와 같이 복수의 조건을 처리할 수 있다.

let message = (age < 3) ? '아기야 안녕?' :
  (age < 18) ? '안녕!' :
  (age < 100) ? '환영합니다!' :
  '나이가 아주 많으시거나, 나이가 아닌 값을 입력 하셨군요!';

처음 이 코드를 보았을 때 해석이 잘 안되었는데 결국은 (age < 3), (age < 18), (age < 100)를 순차적으로 검사하는 코드이다.
해당 코드는 if~else를 이용해 다음과 같이 바꿀 수 있다.

if (age < 3) {
  message = '아기야 안녕?';
} else if (age < 18) {
  message = '안녕!';
} else if (age < 100) {
  message = '환영합니다!';
} else {
  message = '나이가 아주 많으시거나, 나이가 아닌 값을 입력 하셨군요!';
}

부적절한 ? 사용

삼항 연산자는 조건에 따라 반환값을 달리하려는 목적으로 만들어졌다.
그러면 다음과 같이 코드를 작성한다면 어떨까?

let company = prompt('자바스크립트는 어떤 회사가 만들었을까요?', '');

(company == 'Netscape') ?
   alert('정답입니다!') : alert('오답입니다!');

개발자 입장에서는 if문을 사용할 때보다 코드 길이가 짧아져 매력적일 수 있으나, 삼항 연산자의 목적에 부합하지 않아 오히려 가독성을 해칠 수 있다.

따라서 실행되는 표현식을 처리할 때에는 다음과 같이 적어주는 것이 좋다.

let company = prompt('자바스크립트는 어떤 회사가 만들었을까요?', '');

if (company == 'Netscape') {
  alert('정답입니다!');
} else {
  alert('오답입니다!');
}

논리 연산자

자바스크립트에는 ||, &&, ! 이렇게 3개의 논리 연산자가 있다.

|| (OR)

OR 연산자는 다음 순서에 따라 연산을 수행한다.

result = value1 || value2 || value3;
  1. 가장 왼쪽 피연산자부터 시작해 오른쪽으로 나아가며 피연산자를 boolean 형으로 바꿔가며 평가한다.
  2. 변환 후 그 값이 true이면 연산을 멈추고 해당 피연산자의 변환 전 원래 값을 반환한다.
  3. 피연산자 모두를 평가한 경우, 즉 모든 피연산자가 false로 평가되는 경우에는 마지막 피연산자를 반환한다.

여기서 보면 반환 값이 boolean으로 변환된 값이 아니라 원래 값이다.
다음과 같은 식을 실행하면 어떠한 결과가 나올까?

alert( undefined || null || 0 );

undefined, null, 0 은 모두 falsy한 값이기 때문에 마지막 0이 alert 창에 뜨게 될 것이다.

✅ 다음과 같은 OR 연산자의 특성을 여러 용도로 사용할 수 있다.

1. 변수 또는 표현식으로 구성된 목록에서 첫번쨰 truthy 얻기

말이 어려우니 예시를 바로 보자.

let firstName = "";
let lastName = "";
let nickName = "바이올렛";

alert( firstName || lastName || nickName || "익명"); //바이올렛

순차적으로 값을 boolean으로 변환한 결과 nickname에서 가장 먼저 true가 나오기 때문에 반환 값은 "바이올렛"이 된다.
실명, 닉네임, 익명을 모두 활용하는 서비스에서 유용하게 쓸 수 있을 것 같다.

2. 단락 평가

왼쪽 조건이 falsy일 때만 명령어를 실행하고자 할 때 자주 쓰인다.

true || alert("not printed");
false || alert("printed");

첫번째 줄의 경우, true인 경우 평가를 멈추기 떄문에 alert가 실행되지 않는다.
두번째 줄의 경우, alert("print")에서 연산이 멈추기 때문에 alert창을 볼 수 있다.

&& (AND)

&&는 다음과 같은 순서로 작동한다.

  1. 가장 왼쪽 피연산자부터 시작해 오른쪽으로 나아가며 피연산자를 boolean 형으로 바꿔가며 평가한다.
  2. 변환 후 그 값이 false이면 연산을 멈추고 해당 피연산자의 변환 전 원래 값을 반환한다.
  3. 피연산자 모두를 평가한 경우, 즉 모든 피연산자가 true로 평가되는 경우에는 마지막 피연산자를 반환한다.

OR과 비슷한 알고리즘으로 작동한다는 것을 알 수 있다.
다음과 같은 속성을 사용하면 OR과 비슷하게 처음으로 falsy가 나오는 값을 확인할 수 있다.

alert( 1 && 5 ); // 5
alert( 1 && 2 && null && 3 ); // null

||, && 사용시 주의할 사항

  1. &&의 우선순위가 ||보다 높다.
    a && b || c && d(a && b) || (c && d)과 같이 동작한다.
  2. if를 ||, &&으로 대체하지 말자. 가독성이 떨어진다.
// ✅ 조건, 그리고 해당 조건에 대한 실행의 관계가 잘 보이지 않는다. 
(x > 0) && alert( '0보다 큽니다!' );
// ✅ 가독성이 훨씬 개선되었다. 
if (x > 0) alert( '0보다 큽니다!' );

! (NOT)

!의 작동 원리는 다음과 같다.

result = !value;
  1. 피연산자를 불린형(true / false)으로 변환합니다.
  2. 1에서 변환된 값의 역을 반환합니다.

!을 두개 연달아서 !!와 같이 사용하면 값을 불린형으로 변환할 수 있다.

alert( !!"non-empty string" ); // true
alert( !!null ); // false

첫번째 !이 값을 boolean형으로 만들어 역으로 만들고, 두번째 !는 첫번째 !이 반환한 값의 역을 반환한다.
결국 원래 값의 boolean형을 얻을 수 있는 것이다.

✅ !!는 내장함수 Boolean으로 대체할 수도 있다.

alert( Boolean("non-empty string") ); // true

함수 표현식

자바스크립트에서는 함수를 특별한 동작을 하는 구조가 아닌, 특별한 종류의 값으로 취급한다.
(일반적인 값이 데이터를 나타낸다면, 함수는 동작을 나타내는 값이다.)

이를 보여주는 것이 함수 표현식이다.

let sayHi = function() {
  alert( "Hello" );
};

다음과 같이 변수에 값을 할당하는 것처럼 변수에 함수를 할당할 수 있다.
즉, 함수를 값으로 취급하는 것이다.
따라서 값에 할 수 있는 일을 함수에도 할 수 있다.

가장 대표적인 것이 변수를 복사해 다른 변수에 할당하는 것처럼 함수를 복사해 다른 변수에 할당하는 것이다.

function sayHi() {   // (1) 함수 생성
  alert( "Hello" );
}

//✅ let func = sayHi();이 아닌 것에 유의하자. sayHi()와 같이 쓰면 함수 그 자체가 아니라 반환값이 변수에 저장된다. 
let func = sayHi;    // (2) 함수 복사

func(); // Hello     // (3) 복사한 함수를 실행
sayHi(); // Hello

콜백 함수

함수를 함수의 인수로 전달하고, 필요하다면 인수로 전달한 해당 함수를 나중에 호출하는 것이 콜백함수의 개념이다.

function ask(question, yes, no) {
  if (confirm(question)) yes()
  else no();
}

function showOk() {
  alert( "동의하셨습니다." );
}

function showCancel() {
  alert( "취소 버튼을 누르셨습니다." );
}

ask("동의하십니까?", showOk, showCancel);

ask 함수의 인수로 들어간 showOk와 showCancel이 콜백함수이다.

다음과 같이 함수 표현식을 사용하면 코드 길이를 짧게 만들 수 있다.

function ask(question, yes, no) {
  if (confirm(question)) yes()
  else no();
}

ask(
  "동의하십니까?",
  function() { alert("동의하셨습니다."); },
  function() { alert("취소 버튼을 누르셨습니다."); }
);

ask 안에 함수가 선언되어 있는데, 이렇게 이름 없이 선언한 함수를 익명 함수라고 한다.
익명 함수는 변수에 할당된 것이 아니기 때문에 ask 바깥에서는 접근 할 수 없다.

함수 표현식 vs 함수 선언문

1. 문법

// ✅ 함수 표현식
let sum = function(a, b) {
  return a + b;
};
// ✅ 함수 선언문
function sum(a, b) {
  return a + b;
}

2. 함수 생성 시기

함수 표현식 : 실제 실행 흐름이 해당 함수에 도달했을 때 함수를 생성한다.
함수 선언문 : 함수 선언문이 정의되기 전에도 호출할 수 있다.

sayHi("John"); // Hello, John

function sayHi(name) {
  alert( `Hello, ${name}` );
}

함수가 선언되기도 전에 사용했는데 alert창이 제대로 출력되는 것이 이상하다고 느낄 수도 있지만 함수 선언문, sayHi는 스크립트 실행 준비 단계에서 생성되기 때문에, 스크립트 내 어디에서든 접근할 수 있다.

자바스크립트의 내부 알고리즘에서 스크립트를 실행하기 전 준비단계에서 전역에 선언된 함수 선언문을 찾고, 해당 함수를 생성한다.
즉, 스크립트가 진짜 실행되기 전 "초기화 단계"에서 함수 선언 방식으로 정의한 함수가 먼저 생성되는 것이다.
(나는 자바스크립트 내부 알고리즘이 스크립트를 먼저 쓱 훑은 후 함수 선언식만 골라서 먼저 생성한다는 말로 이해했다.)

sayHi("John"); // error!

let sayHi = function(name) {  
  alert( `Hello, ${name}` );
};

하지만 함수 표현식으로 선언한 sayHi는 실행 흐름이 표현식에 다다랐을 때 만들어지기 때문에 함수 선언 전에 실행할 수 없다.

3. 스코프

함수 선언문 : 엄격모드(use strict로 엄격모드를 활성화해야만 ES6 변경 사항의 대부분을 적용할 수 있다.)에서 함수 선언문이 코드 블록 내에 위치하면 블록 내 어디서든 함수를 접근할 수 있다. 하지만, 블록 밖에서는 접근할 수 없다.

let age = 16;

if (age < 18) {
  welcome();         //  함수 선언문은 함수가 선언된 블록 내 어디서든 유효하다       
                         
  function welcome() {    
    alert("안녕!");       
  }                      
                       
  welcome();           //  함수 선언문은 함수가 선언된 블록 내 어디서든 유효하다  

} else {
  function welcome() {
    alert("안녕하세요!");
  }
}

welcome(); // Error: welcome is not defined

다음과 같이 함수 선언문을 사용하면 코드 블록 밖에서 사용시 에러를 발생시키지만, 함수가 위치한 블록 내에서는 함수 선언 전과 후 언제든 접근할 수 있다.

함수 표현식 : 함수가 위치한 코드 블록 밖에서 사용이 가능하다.

let age = prompt("나이를 알려주세요.", 18);

if (age === 18) {

  welcome(); //✅ 함수 표현식이기 때문에 선언 전에 접근할 수 없다. (에러 발생)

  welcome = function() {
    alert("안녕!");
  };
} 

welcome(); //안녕하세요!

주의 사항

✅ 자바스크립트에서는 함수 이름 옆에 괄호를 써주지 않으면 실행되지 않는다.

function sayHi() {
  alert( "Hello" );
}

alert( sayHi ); 

위 코드의 실행결과는 다음과 같다.

괄호를 적어주지 않은 함수가 소스 코드가 문자형으로 바뀌어 값으로써 출력이 된 것이다.

✅ 함수는 값이라면서 왜 세미 콜론은 붙지 않나요?

이유는 중괄호로 만든 코드 블록의 끝에는 세미 콜론이 없어도 되기 때문입니다.

화살표 함수 기본

화살표 함수는=> 왼쪽에 있는 인수를 이용해 => 오른쪽에 있는 표현식을 평가하는 방식입니다.

만약 오른쪽에 있는 표현식이 한 줄이라면 따로 return을 명시해주지 않아도 되지만, 여러 줄이라면 중괄호로 표현식을 감싸고 return을 명시해야합니다.

let sum = (a, b) => a + b;
// 한 줄뿐이라 return이 필요하지 않다. 

let sum = (a, b) => {
  let result = a + b;
  return result; // 중괄호를 사용했다면, return 지시자로 결괏값을 반환해주어야 한다. 
};
profile
🌱Connecting the dots🌱
post-custom-banner

1개의 댓글

comment-user-thumbnail
2023년 4월 16일

덕분에 조건 처리 및 논리 연산자, 함수에 대해 헷갈렸던 부분 다시 한번 짚고 넘어갈 수 있었어요!
특히 개념 하나 하나마다 적절한 예시를 들어주셔서 더 잘 들어왔던 것 같네용 좋은 글 감사합니다~🌞🌞

답글 달기