제어문 & 타입 변환과 단축 평가 & 객체 리터럴

오늘 공부한 내용

  • 제어문
  • 타입 변환과 단축 평가
  • 객체 리터럴

제어문

제어문은 조건에 따라 코드 블록을 실행(조건문)하거나 반복 실행(반복문)할 때 사용한다.

블록문

0개 이상의 문을 중괄호로 묶은 것으로, 코드 블록 또는 블록이라고 부르기도 한다. 블록문은 문의 종료를 의미하는 자체 종결성을 갖기 때문에 블록문 끝에는 세미콜론을 붙이지 않는다.

조건문

주어진 조건식의 평과 결과에 따라 코드 블록의 실행을 결정한다.

if … else 문

논리적 참 또는 거짓에 따라 실행할 코드 블록을 결정한다. if 문의 조건식은 불리언 값으로 평가되어야 한다. 불리언 값이 아닌 값은 암묵적으로 불리언 값으로 형변환된다.

if (조건식1) {
    // 조건식1이 참이면 실행
) else if (조건식2) {
    // 조건식2가 참이면 실
}
else {
    // 조건식1, 조건식2가 모두 거짓이면 실행
}

else if 문과 else 문은 옵션. 코드 블록 내의 문이 하나뿐이라면 중괄호 생략 가능. 이는 삼항 조건 연산자로 바꿔 쓸 수 있다.

조건식 ? 표현식1 : 표현식2

조건식이 참이면 표현식1이 실행되고 거짓이면 표현식2가 실행된다.

삼항 조건 연산자는 값으로 평가되는 표현식을 만들기 때문에 값처럼 사용할 수 있다. 즉, 변수에 할당할 수 있다.

if … else 문은 값처럼 사용할 수 없기 때문에 변수에 할당할 수 없다.

변수에 할당 - 삼항 조건 연산자가 가독성이 좋다

조건에 따라 실행해야 할 내용이 복잡하다 - if … else 문이 가독성이 좋다

(+) early return

Early Return이란 특정 조건이 만족할 때 if문 내에서 Return하여 함수를 미리 종료하는 것이다. else를 제거하여 코드 구조를 단순하게 만들어주는 패턴이다.

function greetUser(isLoggedIn) {
    if (isLoggedIn) {
        console.log("안녕하세요!");
    } else {
        console.log("로그인이 필요합니다.");
    }
}

function greetUser(isLoggedIn) {
    if (!isLoggedIn) {
        console.log("로그인이 필요합니다.");
        return;
    }

    console.log("안녕하세요! 환영합니다.");
}
  • 장점

    • 조건 검사와 실행 코드가 분리되어 코드 가독성 향상

    • 불필요한 중첩 조건문을 제거 - 들여쓰기가 줄어들어 읽기 쉽다

  • 단점

    • 함수 반환이 분산되어 오히려 가독성이 떨어질 수 있음

항상 적용되는 방법이 아니라 상황에 맞게 사용할 것. early return이 오히려 코드를 복잡하게 만들 수 있기에. 간결한 코드는 if … else 문이 명확할 수 있다.

switch 문

주어진 표현식을 평가하여 그 값과 일치하는 표현식을 갖는 case 문으로 실행 흐름을 옮긴다. switch 문의 표현식과 일치하는 case 문이 없다면 실행 순서는 default 문으로 이동. default 문은 옵션.

switch (표현식) {
    case 표현식1:
        switch 문의 표현식과 표현식1이 일치하면 실행
        break
    case 표현식2:
        switch 문의 표현식과 표현식2가 일치하면 실행
        break
    default:
        switch 문의 표현식과 일치하는 case 문이 없을  실행
}

siwtch 문은 논리적 참, 거짓보다는 다양한 상황에 따라 실행할 코드 블록을 결정할 때 사용한다. 여러 개의 case 문을 하나의 조건으로 사용할 때 유용하다.

break 문은 코드 블록에서 탈출하는 역할. case 문을 실행한 후 switch 문을 탈출하지 않고 switch 문이 끝날 때까지 이후의 모든 case 문과 default 문을 실행하는 것을 폴스루(fall through)라고 한다.

반복문

조건식의 평가 결과가 참인 경우 코드 블록을 실행한다. 조건식이 거짓일 때까지 조건식을 다시 평가하여 코드 블록을 재실행한다.

for 문

조건식이 거짓으로 평가될 때까지 코드 블록을 반복 실행한다..

for (변수 선언문 또는 할당문; 조건식; 증감식;) {
    조건식이 참인 경우 반복 실행
}

for 문의 변수 선언문, 조건식, 증감식은 모두 옵션이다. 어떤 식도 선언하지 않으면 무한루프가 된다. for (;;) { ... }

for 문 내에 for 문을 중첩해 사용할 수 있다.

while 문

주어진 조건식의 평가 결과가 참이면 코드 블록을 계속해서 반복 실행한다.

for 문은 반복 횟수가 명확할 때, while 문은 반복 횟수가 불명확할 때 주로 사용.

var count = 0;

while (count < 3) {
    console.log(count);
    count++;
}

while문은 평가 결과가 거짓이 되면 코드 블록을 실행하지 않고 종료.

do … while

코드 블록을 먼저 실행하고 조건식을 평가한다. 따라서 코드 블록은 무조건 한 번 이상 실행된다.

var count = 0;

do {
    console.log(count);
    count++;
} while (count < 3);

break 문

break 문은 코드 레이블 문, 반복문, switch 문의 코드 블록을 탈출한다.

레이블 문이란 식별자가 붙은 문. 프로그래밍의 실행 순서를 제어하는데 사용된다. siwtch 문의 case 문과 default 문도 테이블 문이다.

foo: {
    console.log(1);
    break foo;
    console.log(2); // 실행 X
}

레이블 문은 중첩된 for 문 외부로 탈출할 때 유용하지만 그 밖의 경우에는 일반적으로 권장하지 않는다. 프로그램의 흐름이 복잡해져서 가독성이 나빠지고 오류를 발생시킬 가능성이 높아지기 떄문.

continue 문

반복문의 코드 블록 실행을 현 지점에서 중단하고 반복문의 증감식으로 실행 흐름으로 이동시킨다. break 문처럼 반복문을 탈출하는 것은 아니다.

let text = '';

for (let i = 0; i < 10; i++) {
  if (i === 3) {
    continue;
  }
  text = text + i;
}

console.log(text); // "012456789"

if 문 내에서 실행해야 할 코드가 길다면 continue 문을 사용하면 가독성이 좋다. 들여쓰기가 한 단계 줄어들기 때문에

💬 반복문은 어느 프로그래밍 언어든 비슷하니 빠르게 훑고 패스

타입 변환과 단축 평가

타입 변환이란?

개발자가 의도적으로 값의 타입을 변환하는 것을 명시적 타입 변환 또는 타입 캐스팅이라 한다. 이와 반대로 자바스크립트 엔진에 의해 암묵적으로 타입이 변환되는 것을 암묵적 타입 변환 또는 타입 강제 변환이라 한다.

기존 원시 값을 직접 변경하는 것은 아니다. 기존 원시 값을 사용해 다른 타입의 새로운 원시 값을 생성한다.

코드를 예측하기 위해 타입 변환이 어떻게 동작하는지 정확히 이해하고 사용해야 한다.

💬 충격이었던 JS https://jsisweird.com/

암묵적 타입 변환

자바스크립트 엔진은 표현식을 평가할 때 개발자의 의도와는 상관없이 코드의 문맥을 고려해 암묵적으로 데이터 타입을 강제 변환할 때가 있다.

'10' + 2 // '102'
5 * '10' // 50
!0 // true 

암묵적 타입 변환이 발생하면 원시 타입 중 하나로 타입을 자동 변환한다.

문자열 타입으로 변환

+ 연산자는 피연산자 중 하나 이상이 문자열이면 문자열 연결 연산자로 동작한다. 문자형으로의 변환은 대부분 예측 가능한 방식으로 일어난다.

'10' + 2 // '102'
NaN + '' // "NaN"
Infinity + '' // "Infinity"
true + '' // "true"
null + '' // "null"
undefined + '' // "undefined"
({}) + '' // "[object object]"
[] + '' // ""
[10, 20] + '' // "10,20"

숫자 타입으로 변환

산술 연산자 표현식을 평가하기 위해 산술 연산자의 피연산자 중에서 숫자 타입이 아닌 피연산자를 숫자 타입으로 암묵적 타입 변환한다. 숫자 타입으로 변환할 수 없는 경우는 NaN으로 평가된다.

1 - '1' // 0
1 / 'one' // NaN

비교 연산자는 불리언 값을 만든다. 비교 연산자는 피연산자의 크기를 비교하므로 피연산자는 숫자 타입이어야 한다.

'1' > 0 // true

숫자 타입 아닌 값을 숫자 타입으로 암묵적 타입 변환을 수행할 때,  + 단항 연산자는 피연산자가 숫자 타입의 값이 아니면 숫자 타입의 값으로 암묵적 타입 변환을 수행한다.

+'' // 0
+'5' // 5
-'3' // -3
+true // 1
+false // 0
+'one' // NaN
+{} // NaN
+[] // 0
+[1] // 1
+[1, 2] // NaN

불리언 타입으로 변환

자바스크립트 엔진은 불리언 타입이 아닌 값을 Truthy 값(참으로 평가되는 값) 또는 Falsy 값(거짓으로 평가되는 값)으로 구분한다. 불리언 값으로 평가될 때 Truthy값은 true로, Falsy 값은 false로 암묵적 타입 변환된다.

  • false로 평가되는 Falsy 값

    • false

    • undefined

    • null

    • 0, -0

    • NaN

    • ”” (빈 문자열)

💬 비어있다고 느껴지는 값은 false, 그 외의 값은 true

명시적 타입 변환

명시적으로 타입을 변경하는 방법은 여러가지가 있다.

문자열 타입으로 변환

  1. String 생성자 함수를 new 연산자 없이 호출

  2. Object.prototype.toString 메서드 사용

  3. 문자열 연결 연산자 이용

// 1.
String(1) // "1"

// 2.
(1).toString() // "1"

// 3.
1 + ''

💬 문자열로 변환할 때 toString()보다 10 + ''이 간단한 듯

숫자 타입으로 변환

  1. Number 생성자 함수를 new 연산자 없이 호출

  2. parseInt.parseFloat 함수를 사용

  3. + 단항 산술 연산자를 이용

  4. * 산술 연산자를 이용

// 1.
Number('0') // 0

// 2. 
parseInt('0') // 0
parseFloat('3.14') // 3.14

// 3.
+'0' // 0

// 4. 
'0' * 1 // 0

💬 + 연산자는 가끔 사용했는데 1을 곱해서 숫자로 만드는 것은 생각도 못했다..

불리언 타입으로 변환

  1. Boolean 생성자 함수를 new 연산자 없이 호출

  2. ! 부정 논리 연산자를 두 번 사용

// 1.
Boolean('x') // true

// 2.
!!'0' // true

단축 평가

논리 연산자를 사용한 단축 평가

표현식을 평가하는 도중에 평가 결과가 확정된 경우 나머지 평가 과정을 생략하는 것을 단축 평가라고 한다.

논리곱(&&) 연산자는 두 개의 피연산자가 모두 true로 평가될 때 true를 반환한다. 좌항의 피연산자가 true일 때 우항의 피연산자까지 평가해 보아야 표현식을 평가할 수 있다.

➡ 우항의 피연산자가 논리곱 연산자 표현식의 평가 결과를 결정한다. 논리 연산의 결과를 결정하는 두 번째 피연산자를 반환한다.

논리합 연산자(||)는 두 개의 피연산자 중 하나만 true로 평가되어도 true를 반환한다. 첫 번째 피연산자가 true이면 두 번째 피연산자는 평가하지 않아도 표현식을 평가할 수 있다.

➡ 논리 연산의 결과를 결정한 첫 번째 피연산자를 반환한다.

단축 평가 표현식 평가 결과
true | anything
false | anything
true && anything anything
false && anything false

단축 평가를 사용해 if 문을 대체할 수 있다.

  • 어떤 조건이 Truthy 값일 때 활용

    • var done = true;
      var message = '';
          
      message = done && '완료' // '완료'
      
  • 어떤 조건이 Falsy 값일 때 활용

    • var done = false;
      var message = '';
          
      message = done || '미완료' // '미완료''
      

옵셔널 체이닝 연산자

옵셔널 체이닝 연산자 ?.는 좌항의 피연산자가 null 또는 undefined인 경우 undefined를 반환하고, 그렇지 않으면 우항의 프로퍼티 참조를 이어간다. 좌항 피연산자가 Falsy 값이라도 null 또는 undefined가 아니면 우항의 프로퍼티 참조를 이어간다.

var response = '';

var length = response && response.length // ''
var value = response?.value; // undefined

null 병합 연산자

null 병합 연산자 ??는 좌항의 피연산자가 null 또는 undefined인 경우 우항의 피연산자를 반환하고, 그렇지 않으면 좌항의 피연산자를 반환한다. 변수에 기본값을 설정할 때 유용하다.

var color = null ?? 'red' // 'red'
var foo = '' ?? 'default' // ''

좌항 피연산자가 Falsy 값이라도 null 또는 undefined가 아니면 좌항의 피연산자를 그대로 반환한다.

객체 리터럴

객체란?

객체는 0개 이상의 프로퍼티로 구성된 집합이며, 프로퍼티는 키(key)와 값(value)으로 구성된다. 하나의 값만 나타내는 원시 타입과 달리 객체 타입은 다양한 타입의 값을 담을 수 있다.

💬 중복되는 내용은 링크로 대체. TIL 23-10-13

객체 리터럴에 의한 객체 생성

객체 리터럴은 중괄호({ ... }) 내에 0개 이상의 프로퍼티를 정의한다. 변수에 할당되는 시점에 객체를 생성한다.

객체 리터럴의 중괄호는 코드 블록이 아니므로 중괄호 뒤에 세미콜론을 붙이지 않는다.

프로퍼티

객체는 프로퍼티의 집합이며, 프로퍼티는 키와 값으로 구성된다. 프로퍼티를 나열할 때는 쉼표(,)로 구분.

  • 프로퍼티 키: 빈 문자열을 포함하는 모든 문자열 또는 심벌 값

  • 프로퍼티 값: 자바스크립트에서 사용할 수 있는 모든 값

var person = {
    name: 'Lee', // 프로퍼티 키: name, 프로퍼티 값: 'Lee'
    age: 20 // 프로퍼티 키: age, 프로퍼티 
}

프로퍼티 키로 식별자 네이밍 규칙을 따르지 않는 이름은 반드시 따옴표를 사용한다. 예약어를 프로퍼티 키로 사용해도 에러가 발생하지는 않지만 사용을 권장하지는 않는다.

var person = {
    'first-name': 'gildong'
}

이미 존재하는 프로퍼티 키를 중복 선언하면 나중에 선언한 프로퍼티가 덮어쓴다.

메서드

함수는 값으로 취급할 수 있기 때문에 프로퍼티 값으로 사용할 수 있다. 프로퍼티 값이 함수일 경우 일반 함수와 구분하기 위해 메서드라 부른다. 즉, 메서드는 객체에 묶여 있는 함수를 의미한다.

var date = {
  year: 2023,
  month: 10,
  day: 16,
  getDate: function () {
      return `${this.year}.${this.month}.${this.day}`; 
  }
};

프로퍼티 접근

프로퍼티에 접근하는 방법 두 가지

  • 마침표 프로퍼티 접근 연산자(.)를 사용하는 마침표 표기법

  • 대괄호 프로퍼티 접근 연산자([ … ])를 사용하는 대괄호 표기법

var person = {
    name: 'Lee'
}

console.log(person.name)
console.log(person['name'])

대괄호 표기법을 사용하는 경우 프로퍼티 키를 따옴표로 감싸야 한다. 대괄호 프로퍼티 접근 연산자 내에 따옴표로 감싸지 않은 이름을 프로퍼티 키로 사용하면 식별자로 해석한다.

프로퍼티 키가 식별자 네이밍 규칙을 준수하지 않는 이름이면 반드시 대괄호 표기법을 사용해야 한다.

객체에 존재하지 않는 프로퍼티에 접근하면 undefined를 반환한다. 에러가 발생하지 않는다.

프로퍼티 값 갱신

이미 존재하는 프로퍼티에 값을 할당하면 프로퍼티 값이 갱신된다.

var person = { name: 'Lee' }
person.name = 'Kim'
console.log(person) // 'Kim'

프로퍼티 동적 생성

존재하지 않는 프로퍼티에 값을 할당하면 프로퍼티가 동적으로 생성되어 추가되고 프로퍼티 값이 할당된다.

var person = { name: 'Lee' }
person.age = 20
console.log(person) // { name: 'Lee', age: 20 }

프로퍼티 삭제

delete 연산자는 객체의 프로퍼티를 삭제한다.

var person = { name: 'Lee' }
person.age = 20
delete person.age
console.log(person) // { name: 'Lee' }

ES6에서 추가된 객체 리터럴의 확장 기능

프로퍼티 축약 표현

프로퍼티 값으로 변수를 사용하는 경우 변수 이름과 프로퍼티 키가 동일한 이름일 때 프로퍼티 키를 생략할 수 있다.

let x = 1, y = 2

const obj = { x, y }
console.log(obj) // { x: 1, y: 2 }

계산된 프로퍼티 이름

문자열 또는 문자열로 타입 변환할 수 있는 값으로 평가되는 표현식을 사용해 프로퍼티 키를 동적으로 생성할 수도 있다. 프로퍼티 키로 사용할 표현식을 대괄호로 묶어서 사용.

let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple");

let bag = {
  [fruit]: 5,
}; 

console.log(bag.apple) // 5

메서드 축약 표현

메서드를 정의할 때 function 키워드를 생략한 축약 표현을 사용할 수 있다.

var date = {
  year: 2023,
  month: 10,
  day: 16,
  getDate() {
      return `${this.year}.${this.month}.${this.day}`; 
  }
};

부족한 내용 / 궁금한 내용

  • 암묵적 타입 변환의 결과 예상
  • 생성자
  • 메서드 축약 표현으로 정의한 메서드와 프로퍼티에 할당한 함수 동작 차이

느낀점

자바스크립트가 너무나도 유연한 탓에 예상치 못한 결과와 마주칠 때가 있다. 예를 들면

('b'+'a'+ +'a'+'a').toLowerCase() // "banana"

타입 변환을 학습하고 나니 이상한 표현도 이해가 간다. 자바스크립트 문법 공부를 마치면 다시 풀어봐야겠다. https://jsisweird.com/

특히 단축 평가는 React 개발할 때 로딩되면 엘리먼트를 출력하기 위해 종종 썼기에 친숙했다. 앞으로 개발하며 if문 대신에 코드양을 줄이고 가독성을 높이는데 사용해보도록 노력해야 겠다.

객체 파트에서는 객체 개념과 함께 ‘계산된 프로퍼티 이름’은 TypeScript에서 프로퍼티를 정의할 때 쓰던 기능임을 알게 되었다. React나 TypeScript나 자바스크립트 기반인데 참 문법에 대해 몰랐구나 싶다.

카테고리:

업데이트:

댓글남기기