DAY - 03

공부 저장소·2021년 4월 19일
post-thumbnail

자료형

자바스크립트에는 여덟 가지 기본 자료형이 있다.

자바스크립트의 변수는 자료형에 관계없이 모든 데이터일 수 있다. 따라서 변수는 어떤 순간에 문자열일 수 있고 다른 순간엔 숫자가 될 수도 있다.

// no error
let message = "hello";
message = 123456;

위 코드처럼 자료의 타입은 있지만 변수에 저장되는 값의 타입은 언제든지 바꿀 수 있는 언어를 ‘동적 타입(dynamically typed)’ 언어라고 부른다.

숫자형

let n = 123;
n = 12.345;

숫자형엔 일반적인 숫자 외에 Infinity, -Infinity, NaN같은 '특수 숫자 값(special numeric value)'이 포함된다.

  • Infinity는 어떤 숫자보다 큰 특수 값, 무한대(∞)를 나타낸다.

    어느 숫자든 0으로 나누면 무한대를 얻을 수 있다.

alert( 1 / 0 ); // 무한대

Infinity를 직접 참조할 수도 있다.

alert( Infinity ); // 무한대
  • NaN은 계산 중에 에러가 발생했다는 것을 나타내주는 값이다. 부정확하거나 정의되지 않은 수학 연산을 사용하면 계산 중에 에러가 발생하는데, 이때 NaN이 반환된다.
alert( "숫자가 아님" / 2 ); // NaN, 문자열을 숫자로 나누면 오류가 발생합니다.

NaN은 여간해선 바뀌지 않는다. NaN에 어떤 추가 연산을 해도 결국 NaN이 반환된다.

alert( "숫자가 아님" / 2 + 5 ); // NaN

연산 과정 어디에선가 NaN이 반환되었다면, 이는 모든 결과에 영향을 미친다.

문자형

자바스크립트에선 문자열(string)을 따옴표로 묶는다.

let str = "Hello";
let str2 = 'Single quotes are ok too';
let phrase = `can embed another ${str}`;

따옴표는 세 종류가 있다.

큰따옴표: "Hello"
작은따옴표: 'Hello'
역 따옴표(백틱, backtick): ` <- 맥에서는 영타 상태에서만 ₩로 입력 가능
큰따옴표와 작은따옴표는 ‘기본적인’ 따옴표로, 자바스크립트에서는 이 둘에 차이를 두지 않는다.

역 따옴표로 변수나 표현식을 감싼 후 ${…}안에 넣어주면, 아래와 같이 원하는 변수나 표현식을 문자열 중간에 손쉽게 넣을 수 있다.

let name = "John";

// 변수를 문자열 중간에 삽입
alert( `Hello, ${name}!` ); // Hello, John!

// 표현식을 문자열 중간에 삽입
alert( `the result is ${1 + 2}` ); // the result is 3

${…} 안에는 name 같은 변수나 1 + 2 같은 수학 관련 표현식을 넣을 수 있다. 물론 더 복잡한 표현식도 넣을 수 있죠. 무엇이든 들어갈 수 있다. 이렇게 문자열 중간에 들어간 변수나 표현식은 평가가 끝난 후 문자열의 일부가 된다.

※ 큰따옴표나 작은따옴표를 사용하면 중간에 표현식을 넣을 수 없다는 점에 주의하기 바란다. 이 방법은 역 따옴표를 써야만 가능하다.

불린형

불린형(논리 타입)은 true와 false 두 가지 값밖에 없는 자료형이다.

불린형은 긍정이나 부정을 나타내는 값을 저장할 때 사용한다. true는 긍정, false는 부정을 의미한다.

예시:

let nameFieldChecked = true; // 네, name field가 확인되었습니다(checked).
let ageFieldChecked = false; // 아니요, age field를 확인하지 않았습니다(not checked)

불린값은 비교 결과를 저장할 때도 사용된다.

let isGreater = 4 > 1;

alert( isGreater ); // true (비교 결과: "yes")

‘null’ 값

null 값은 지금까지 소개한 자료형 중 어느 자료형에도 속하지 않는 값이다.

null 값은 오로지 null 값만 포함하는 별도의 자료형을 만든다.

let age = null;

자바스크립트의 null은 자바스크립트 이외 언어의 null과 성격이 다르다. 다른 언어에선 null을 '존재하지 않는 객체에 대한 참조’나 '널 포인터(null pointer)'를 나타낼 때 사용한다.

하지만 자바스크립트에선 null을 ‘존재하지 않는(nothing)’ 값, ‘비어 있는(empty)’ 값, ‘알 수 없는(unknown)’ 값을 나타내는 데 사용한다.

let age = null;은 나이(age)를 알 수 없거나 그 값이 비어있음을 보여줍니다.

‘undefined’ 값

undefined 값도 null 값처럼 자신만의 자료형을 형성한다.

undefined는 '값이 할당되지 않은 상태’를 나타낼 때 사용한다.

변수는 선언했지만, 값을 할당하지 않았다면 해당 변수에 undefined가 자동으로 할당된다.

let age;

alert(age); // 'undefined'가 출력된다.

개발자가 변수에 undefined를 명시적으로 할당하는 것도 가능하긴 하다.

let age = 100;

// 값을 undefined로 바꿉니다.
age = undefined;

alert(age); // "undefined"

이렇게 undefined를 직접 할당하는 걸 권장하진 않는다고 한다. 변수가 ‘비어있거나’ ‘알 수 없는’ 상태라는 걸 나타내려면 null을 사용하자
undefined는 값이 할당되지 않은 변수의 초기값을 위해 예약어로 남겨두자

객체와 심볼

객체(object)형은 특수한 자료형이다.

객체형을 제외한 다른 자료형은 문자열이든 숫자든 한 가지만 표현할 수 있기 때문에 원시(primitive) 자료형이라 부른다. 반면 객체는 데이터 컬렉션이나 복잡한 개체(entity)를 표현할 수 있다.

이런 특징 때문에 자바스크립트에서 객체는 좀 더 특별한 취급을 받는다. 자세한 내용은 원시형을 배우고 난 후에...

심볼(symbol)형은 객체의 고유한 식별자(unique identifier)를 만들 때 사용된다. 심볼형에 대해선 객체를 학습하고 난 후에...

typeof 연산자

typeof 연산자는 인수의 자료형을 반환합니다.
typeof 연산자는 두 가지 형태의 문법을 지원합니다.

연산자: typeof x
함수: typeof(x)
괄호가 있든 없든 결과가 동일하다.

typeof x를 호출하면 인수의 자료형을 나타내는 문자열을 반환한다.

typeof undefined // "undefined"

typeof 0 // "number"
typeof true // "boolean"

typeof "foo" // "string"

typeof Symbol("id") // "symbol"

typeof Math // "object"  (1)

typeof null // "object"  (2)

typeof alert // "function"  (3)

또한 출처의 작성자님이 적어주신 마지막 세 줄의 설명으로 쓰여있는 것은.

Math는 수학 연산을 제공하는 내장 객체이므로 "object"가 출력됩니다. Math에 대해선 숫자형 챕터에서 학습하도록 하겠습니다. 내장 객체는 객체형이라는 것을 알려주기 위해 이런 예시를 작성해 보았습니다.
typeof null의 결과는 "object"입니다. null은 별도의 고유한 자료형을 가지는 특수 값으로 객체가 아니지만, 하위 호환성을 유지하기 위해 이런 오류를 수정하지 않고 남겨둔 상황입니다. 언어 자체의 오류이므로 null이 객체가 아님에 유의하시기 바랍니다.
typeof는 피연산자가 함수면 "function"을 반환합니다. 그러므로 typeof alert는 "function"을 출력해줍니다. 그런데 '함수’형은 따로 없습니다. 함수는 객체형에 속합니다. 이런 동작 방식이 형식적으론 잘못되긴 했지만, 아주 오래전에 만들어진 규칙이었기 때문에 하위 호완성 유지를 위해 남겨진 상태입니다. 한편, 실무에선 이런 특징이 매우 유용하게 사용되기도 합니다.

bigint

내부 표현 방식 때문에 자바스크립트에선 (253-1)(9007199254740991) 보다 큰 값 혹은 -(253-1) 보다 작은 정수는 '숫자형’을 사용해 나타낼 수 없다.

사실 대부분의 상황에서 이런 제약사항은 문제가 되지 않는다. 그렇지만 암호 관련 작업같이 아주 큰 숫자가 필요한 상황이거나 아주 높은 정밀도로 작업을 해야 할 때는 이런 큰 숫자가 필요하다.

BigInt형은 표준으로 채택된 지 얼마 안 된 자료형으로, 길이에 상관없이 정수를 나타낼 수 있다.

BigInt형 값은 정수 리터럴 끝에 n을 붙이면 만들 수 있다.

// 끝에 'n'이 붙으면 BigInt형 자료입니다.
const bigInt = 1234567890123456789012345678901234567890n;

alert, prompt, confirm을 이용한 상호작용

alert

이 함수가 실행되면 사용자가 ‘확인(OK)’ 버튼을 누를 때까지 메시지를 보여주는 창이 계속 떠있게 된다.

alert("Hello");

메시지가 있는 작은 창은 모달 창(modal window) 이라고 부른다. '모달’이란 단어엔 페이지의 나머지 부분과 상호 작용이 불가능하다는 의미가 내포되어 있다. 따라서 사용자는 모달 창 바깥에 있는 버튼을 누른다든가 하는 행동을 할 수 없다. 확인 버튼을 누르기 전까지 말이다.

prompt

브라우저에서 제공하는 prompt 함수는 두 개의 인수를 받는다.

result = prompt(title, [default]);

함수가 실행되면 텍스트 메시지와 입력 필드(input field), 확인(OK) 및 취소(Cancel) 버튼이 있는 모달 창이 띄워진다.

title

사용자에게 보여줄 문자열

default

입력 필드의 초깃값(선택값)
인수를 감싸는 대괄호 [...]의 의미
default를 감싸는 대괄호는 이 매개변수가 필수가 아닌 선택값이라는 것을 의미한다.

사용자는 프롬프트 대화상자의 입력 필드에 원하는 값을 입력하고 확인을 누를 수 있다. 값을 입력하길 원하지 않는 경우는 취소(Cancel) 버튼을 누르거나 Esc를 눌러 대화상자를 빠져나가면 된다.

prompt 함수는 사용자가 입력 필드에 기재한 문자열을 반환한다. 사용자가 입력을 취소한 경우는 null이 반환된다.

예시:

let age = prompt('나이를 입력해주세요.', 100);

alert(`당신의 나이는 ${age}살 입니다.`); // 당신의 나이는 100살입니다.

Internet Explorer(IE)에서는 항상 '기본값’을 넣어주자
프롬프트 함수의 두 번째 매개변수는 선택사항이지만, 이 매개변수가 없는 경우 IE는 "undefined"를 입력 필드에 명시한다.

아래 코드를 IE에서 실행해 보자

let test = prompt("Test");

IE 사용자를 비롯한 모든 사용자에게 깔끔한 프롬프트를 보여주려면 아래와 같이 두 번째 매개변수를 항상 전달해 줄 것을 권장한다.

let test = prompt("Test", ''); // <-- ,''로 IE 사용자를 위한 매개변수 처리를 해주어야 한다.

컨펌 대화상자

result = confirm(question);
confirm 함수는 매개변수로 받은 question(질문)과 확인 및 취소 버튼이 있는 모달 창을 보여줍니다.

사용자가 확인버튼를 누르면 true, 그 외의 경우는 false를 반환합니다.

let isBoss = confirm("당신이 주인인가요?");

alert( isBoss ); // 확인 버튼을 눌렀다면 true가 출력됩니다.

브라우저는 사용자와 상호작용할 수 있는 세 가지 함수를 제공합니다.

상호작용 요약

위 함수들은 모두 모달 창을 띄워주는데, 모달 창이 떠 있는 동안은 스크립트의 실행이 일시 중단된다. 사용자가 창을 닫기 전까진 나머지 페이지와 상호 작용이 불가능하다.

지금까지 살펴본 세 함수엔 두 가지 제약사항이 있다.

  1. 모달 창의 위치는 브라우저가 결정하는데, 대개 브라우저 중앙에 위치합니다.
  2. 모달 창의 모양은 브라우저마다 다릅니다. 개발자는 창의 모양을 수정할 수 없습니다.

이런 제약사항은 간결성을 위해 치러야 할 대가다. 창을 더 멋지게 꾸미고 복잡한 상호작용을 가능하게 해주는 다른 방법도 있긴 하지만, '멋을 위한 부가 기능’이 필요하지 않다면 지금까지 소개한 기본 메서드만으로 충분하다.

형 변환

함수와 연산자에 전달되는 값은 대부분 적절한 자료형으로 자동 변환된다. 이런 과정을 "형 변환(type conversion)"이라고 한다.

alert가 전달받은 값의 자료형과 관계없이 이를 문자열로 자동 변환하여 보여주는 것이나, 수학 관련 연산자가 전달받은 값을 숫자로 변환하는 경우가 형 변환의 대표적인 예시이다.

이 외에 전달받은 값을 의도를 갖고 원하는 타입으로 변환(명시적 변환)해 주는 경우도 형 변환이라고 할 수 있다.

문자형으로 변환

문자형으로의 형 변환은 문자형의 값이 필요할 때 일어난다.

alert메서드는 매개변수로 문자형을 받기 때문에, alert(value)에서 value는 문자형이어야만 한다. 만약, 다른 형의 값을 전달받으면 이 값은 문자형으로 자동 변환된다.

String(value) 함수를 호출해 전달받은 값을 문자열로 변환 할 수도 있다.

let value = true;
alert(typeof value); // boolean

value = String(value); // 변수 value엔 문자열 "true"가 저장됩니다.
alert(typeof value); // string

false는 문자열 "false"로, null은 문자열 "null"로 변환되는 것과 같이, 문자형으로의 변환은 대부분 예측 가능한 방식으로 일어난다.

숫자형으로 변환

숫자형으로의 변환은 수학과 관련된 함수와 표현식에서 자동으로 일어난다.

숫자형이 아닌 값에 나누기 /를 적용한 경우와 같이 말이다.

alert( "6" / "2" ); // 3, 문자열이 숫자형으로 자동변환된 후 연산이 수행된다.

Number(value) 함수를 사용하면 주어진 값(value)을 숫자형으로 명시해서 변환할 수 있다.

let str = "123";
alert(typeof str); // string

let num = Number(str); // 문자열 "123"이 숫자 123으로 변환됩니다.

alert(typeof num); // number

숫자형 값를 사용해 무언가를 하려고 하는데 그 값을 문자 기반 폼(form)을 통해 입력받는 경우엔, 이런 명시적 형 변환이 필수입니다.

한편, 숫자 이외의 글자가 들어가 있는 문자열을 숫자형으로 변환하려고 하면, 그 결과는 NaN이 됩니다. 예시를 살펴봅시다.

let age = Number("임의의 문자열 123");

alert(age); // NaN, 형 변환이 실패합니다.

아래는 숫자형으로 변환 시 적용되는 규칙입니다.

alert( Number("   123   ") ); // 123
alert( Number("123z") );      // NaN ("z"를 숫자로 변환하는 데 실패함)
alert( Number(true) );        // 1
alert( Number(false) );       // 0

불린형으로 변환

불린형으로의 변환은 아주 간단하다.

이 형 변환은 논리 연산을 수행할 때 발생한다. Boolean(value)를 호출하면 명시적으로 불리언으로의 형 변환을 수행할 수 있다.

불린형으로 변환 시 적용되는 규칙은 다음과 같다.

숫자 0, 빈 문자열, null, undefined, NaN과 같이 직관적으로도 “비어있다고” 느껴지는 값들은 false가 된다.
그 외의 값은 true로 변환된다.

alert( Boolean(1) ); // 숫자 1(true)
alert( Boolean(0) ); // 숫자 0(false)
alert( Boolean("hello") ); // 문자열(true)
alert( Boolean("") ); // 빈 문자열(false)

※주의: 문자열 "0"은 true입니다.

기본 연산자와 수학

‘단항’, ‘이항’, ‘피연산자’

앞으로 자주 등장하게 될 용어 몇 가지를 정리해 보겠다.

피연산자(operand) 는 연산자가 연산을 수행하는 대상이다. 5 * 2에는 왼쪽 피연산자 5와 오른쪽 피연산자 2, 총 두 개의 피연산자가 있다.
'피연산자’는 '인수(argument)'라는 용어로 불리기도 한다.

피연산자를 하나만 받는 연산자는 단항(unary) 연산자 라고 부른다. 피연산자의 부호를 뒤집는 단항 마이너스 연산자 -는 단항 연산자의 대표적인 예 이다.

let x = 1;

x = -x;
alert( x ); // -1, 단항 마이너스 연산자는 부호를 뒤집는다.

두 개의 피연산자를 받는 연산자는 이항(binary) 연산자 라고 부릅니다. 마이너스 연산자는 아래와 같이 이항 연산자로 쓸 수도 있다.

let x = 1, y = 3;
alert( y - x ); // 2, 이항 마이너스 연산자는 뺄셈을 해준다.

위와 같이 부호를 반전해주는 단항 마이너스 연산자와 뺄셈에 쓰이는 이항 마이너스 연산자(뺄셈 연산자)는 기호는 같지만 수행하는 연산이 다르다.
두 연산을 구분하는 기준은 피연산자의 개수이다.**

※연산자는 내가 알고 있는 + - / % * 를 제외하고 **에 대하여 알아보도록 하겠다

거듭제곱 연산자 **

거듭제곱 연산자(exponentiation operator)를 사용한 a ** b를 평가하면 a를 b번 곱한 값이 반환된다.

alert( 2 ** 2 ); // 4  (2 * 2)
alert( 2 ** 3 ); // 8  (2 * 2 * 2)
alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2)

거듭제곱 연산자는 정수가 아닌 숫자에 대해서도 동작한다. 1/2을 사용하면 제곱근을 구할 수 있다.

alert( 4 ** (1/2) ); // 2 (1/2 거듭제곱은 제곱근)
alert( 8 ** (1/3) ); // 2 (1/3 거듭제곱은 세제곱근)

이항 연산자 '+'와 문자열 연결

자바스크립트가 제공하는 특별한 연산자 기능에 대해 살펴보자.

덧셈 연산자 +는 대개 숫자를 더한 결과를 반환한다.

그런데 이항 연산자 +의 피연산자로 문자열이 전달되면 덧셈 연산자는 덧셈이 아닌 문자열을 병합(연결)한다.

let s = "my" + "string";
alert(s); // mystring

따라서 이항 연산자 +를 사용할 때는 피연산자 중 하나가 문자열이면 다른 하나도 문자열로 변환된다는 점에 주의해야 한다.

alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"

첫 번째 피연산자가 문자열인지, 두 번째 피연산자가 문자열인지는 중요하지 않다. 피연산자 중 어느 하나가 문자열이면 다른 하나도 문자열로 변환된다.

좀 더 복잡한 예시로는

alert(2 + 2 + '1' ); // '221'이 아니라 '41'이 출력됩니다.

연산은 왼쪽에서 오른쪽으로 순차적으로 진행되기 때문에 이런 결과가 나왔다. 두 개의 숫자 뒤에 문자열이 오는 경우, 숫자가 먼저 더해지고, 그 후 더해진 숫자와 문자열과의 병합이 일어난다.

이처럼 이항 덧셈 연산자 +는 문자열 연결과 변환이라는 특별한 기능을 제공한다. 다른 산술 연산자가 오직 숫자형의 피연산자만 다루고, 피연산자가 숫자형이 아닌 경우에 그 형을 숫자형으로 바꾸는 것과는 대조적이다.

아래는 뺄셈 -과 나눗셈 / 연산자가 어떻게 문자형 피연산자를 다루는지를 보여준다.

alert( 6 - '2' ); // 4, '2'를 숫자로 바꾼 후 연산이 진행됩니다.
alert( '6' / '2' ); // 3, 두 피연산자가 숫자로 바뀐 후 연산이 진행됩니다.

단항 연산자 +와 숫자형으로의 변환

덧셈 연산자 +는 이항 연산자뿐만 아니라 단항 연산자로도 사용할 수 있다.

숫자에 단항 덧셈 연산자를 붙이면 이 연산자는 아무런 동작도 하지 않는다. 그러나 피연산자가 숫자가 아닌 경우엔 숫자형으로의 변환이 일어난다.

// 숫자에는 아무런 영향을 미치지 않는다.
let x = 1;
alert( +x ); // 1

let y = -2;
alert( +y ); // -2

// 숫자형이 아닌 피연산자는 숫자형으로 변화한다.
alert( +true ); // 1
alert( +"" );   // 0

단항 덧셈 연산자는 짧은 문법으로도 Number(...)와 동일한 일을 할 수 있게 해준다.

개발을 하다 보면 문자열을 숫자로 변환해야 하는 경우가 자주 생깁니다. HTML 폼(form) 필드에서 값을 가져왔는데 그 값이 문자형일 때 같이 말이죠. 실제로 폼에서 가지고 온 값은 대개 문자열 형태이다.

이항 덧셈 연산자를 사용하면 아래와 같이 값이 문자열로 변해서 연결될 것이다.

let apples = "2";
let oranges = "3";

alert( apples + oranges ); // 23, 이항 덧셈 연산자는 문자열을 연결합니다.

원하는 대로 값을 더해주려면, 단항 덧셈 연산자를 사용해 피연산자를 숫자형으로 변화시키면 된다.

let apples = "2";
let oranges = "3";

// 이항 덧셈 연산자가 적용되기 전에, 두 피연산자는 숫자형으로 변화합니다.
alert( +apples + +oranges ); // 5

// `Number(...)`를 사용해서 같은 동작을 하는 코드를 작성할 수 있지만, 더 기네요.
// alert( Number(apples) + Number(oranges) ); // 5

위 식을 수학자가 본다면 불필요한 덧셈 기호에 대해 언급하며 식이 이상하다고 지적할 것이다. 프로그래머라면 아니겠지만 말이다. 위 식은 우리가 의도한 대로 단항 덧셈 연산자가 먼저 문자열을 숫자로 변환시키고, 이항 덧셈 연산자가 그 결과들을 더해주고 있다.

그런데 왜 이항 덧셈 연산자가 적용되기 전에 단항 덧셈 연산자가 먼저 적용되는 이유는 다음에 나오는 연산자의 우선순위 때문이다.

연산자 우선순위

하나의 표현식에 둘 이상의 연산자가 있는 경우, 실행 순서는 연산자의 우선순위(precedence) 에 의해 결정된다.

1 + 2 * 2라는 식이 있을 때 곱셈이 먼저, 그 후에 덧셈이 일어난다는 것을 알고 있을텐데 이런 개념이 연산자 우선순위다.
여기서 곱셈은 덧셈보다 더 높은 우선순위를 가지는 것처럼 말이다.

자바스크립트에서 정의한 연산자 우선순위가 마음에 들지 않는다면, 괄호를 사용하면 된다. 괄호는 모든 연산자보다 우선순위가 높기 때문에 자바스크립트에서 정의한 연산자 우선순위를 무력화시킵니다. 표현식 (1 + 2) * 2에서 괄호로 둘러싼 덧셈 연산자가 먼저 수행되는 것 같이 말이죠.

자바스크립트는 다양한 연산자를 제공하는데, 이 모든 연산자엔 우선순위가 매겨져 있다. 우선순위 숫자가 클수록 먼저 실행된다. 순위가 같으면 왼쪽부터 시작해서 오른쪽으로 연산이 수행된다.

우선순위 테이블 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#table

할당 연산자

무언가를 할당할 때 쓰이는 =도 연산자이다. 이 연산자는 할당(assignment) 연산자라고 불리는데, 우선순위는 3으로 아주 낮다.

x = 2 * 2 + 1과 같은 표현식에서 계산이 먼저 이뤄지고, 그 결과가 x에 할당되는 이유가 바로 이 때문이다.

let x = 2 * 2 + 1;

alert( x ); // 5

값을 반환하는 할당 연산자

=는 연산자이기 때문에 흥미로운 함축성을 내포하고 있다.

자바스크립트에서 대부분의 연산자들은 값을 반환합니다. +와 -뿐만 아니라 = 역시 값을 반환한다..

x = value을 호출하면 value가 x에 쓰여지고, 이에 더하여 value가 반환된다.

let a = 1;
let b = 2;

let c = 3 - (a = b + 1);

alert( a ); // 3
alert( c ); // 0

위 예제에서 표현식 (a = b + 1)은 a에 값을 할당하고, 그 값인 3을 반환한다. 그리고 반환 값은 이어지는 표현식에 사용된다.

괴상한 코드라고 느껴지겠지만, 여러 자바스크립트 라이브러리에서 이런 식으로 할당 연산자를 사용하고 있기 때문에 동작 원리를 이해할 수 있어야 한다.

직접 코드를 작성할 땐 이런 방식을 사용하지 않도록 주의해야겠다.
이런 트릭을 사용하면 코드가 명확하지 않을 뿐만 아니라 가독성도 떨어지기 때문이다.

할당 연산자 체이닝

할당 연산자는 아래와 같이 여러 개를 연결할 수도 있다(체이닝).

let a, b, c;

a = b = c = 2 + 2;

alert( a ); // 4
alert( b ); // 4
alert( c ); // 4

이렇게 할당 연산자를 여러 개 연결한 경우, 평가는 우측부터 진행된다. 먼저 가장 우측의 2 + 2가 평가되고, 그 결과가 좌측의 c, b, a에 순차적으로 할당된다. 모든 변수가 단일 값을 공유하게 된다.

그런데 되도록이면 연산자를 체이닝 하는것 보다 가독성을 위해 아래와 같이 줄을 나눠 코드를 작성하길 권유드린다고 한다.

c = 2 + 2;
b = c;
a = c;

이렇게 작성하면 읽기도 쉽고, 눈을 빠르게 움직이며 코드를 읽을 수 있습니다.

복합 할당 연산자

프로그램을 짜다 보면, 변수에 연산자를 적용하고 그 결과를 같은 변수에 저장해야 하는 경우가 종종 생긴다.

let n = 2;
n = n + 5;
n = n * 2;

이때, +=와 *=연산자를 사용하면 짧은 문법으로 동일한 연산을 수행할 수 있다.

let n = 2;
n += 5; // n은 7이 됩니다(n = n + 5와 동일).
n *= 2; // n은 14가 됩니다(n = n * 2와 동일).

alert( n ); // 14

이런 ‘복합 할당’ 연산자는 산술 연산자와 비트 연산자에도 적용할 수 있습니다. /=, -= 등의 연산자를 만들 수 있다.

복합 할당 연산자의 우선순위는 할당 연산자와 동일하다. 따라서 대부분 다른 연산자가 실행된 후에 복합 할당 연산자가 실행된다.

let n = 2;

n *= 3 + 5;

alert( n ); // 16  (*=의 우측이 먼저 평가되므로, 위 식은 n *= 8과 동일합니다.)

증가·감소 연산자

숫자를 하나 늘리거나 줄이는 것은 자주 사용되는 연산이다.

자바스크립트에서는 이런 연산을 해주는 연산자를 제공한다.

증가(increment) 연산자 ++는 변수를 1 증가시킨다.

let counter = 2;
counter++;      // counter = counter + 1과 동일하게 동작합니다. 하지만 식은 더 짧습니다.
alert( counter ); // 3

감소(decrement) 연산자 --는 변수를 1 감소시킨다.

let counter = 2;
counter--;      // counter = counter - 1과 동일하게 동작합니다. 하지만 식은 더 짧습니다.
alert( counter ); // 1

※증가/감소 연산자는 변수에만 쓸 수 있습니다. 5++와 같이 값에 사용하려고 하면 에러가 발생합니다.

그 외의 연산자

그 외의 연산자로는 비트 연산자와 쉼표 연산자가 있는데 아직 나에게는 필요가 없다고 판단되어 나중에 필요할 때 보도록 링크로 처리해야겠다.
비트 연산자 : https://ko.javascript.info/operators#ref-157

쉼표 연산자 : https://ko.javascript.info/operators#ref-158

비교 연산자

우선 내가 이전부터 알고있는 연산자는 아래로 정리가 된다.

  • 보다 큼·작음: a > b, a < b.
  • 보다 크거나·작거나 같음: a >= b, a <= b.
  • 같음(동등): a == b. 등호 =가 두 개 연달아 오는 것에 유의하세요. a ​​= b와 같이 등호가 하나일 때는 할당을 의미합니다.
  • 같지 않음(부등): 같지 않음을 나타내는 수학 기호 ≠는 자바스크립트에선 a != b로 나타냅니다. 할당연산자 = 앞에 느낌표 !를 붙여서 표시합니다.

하지만 자료형에 따른 비교가 필요하기에 배워야한다...

불린형 반환

다른 연산자와 마찬가지로 비교 연산자 역시 값을 반환한다. 반환 값은 불린형이다.

true가 반환되면, ‘긍정’, ‘참’, '사실’을 의미한다.
false가 반환되면, ‘부정’, ‘거짓’, '사실이 아님’을 의미한다.

alert( 2 > 1 );  // true
alert( 2 == 1 ); // false
alert( 2 != 1 ); // true

반환된 불린값은 다른 여타 값처럼 변수에 할당 할 수 있다.

let result = 5 > 4; // 비교 결과를 변수에 할당
alert( result ); // true

문자열 비교

자바스크립트는 '사전’순으로 문자열을 비교한다. '사전편집(lexicographical)'순 이라고 불리기도 하는 이 기준을 적용하면 사전 뒤쪽의 문자열은 사전 앞쪽의 문자열보다 크다고 판단된다.

실제 단어를 사전에 실을 때 단어를 구성하는 문자 하나하나를 비교하여 등재 순서를 정하는 것과 같이 자바스크립트도 문자열을 구성하는 문자 하나하나를 비교해가며 문자열을 비교한다.

alert( 'Z' > 'A' ); // true
alert( 'Glow' > 'Glee' ); // true
alert( 'Bee' > 'Be' ); // true

이에 적용되는 알고리즘은 아래와 같다.

  1. 두 문자열의 첫 글자를 비교합니다.
  2. 첫 번째 문자열의 첫 글자가 다른 문자열의 첫 글자보다 크면(작으면), 첫 번째 문자열이 두 번째 문자열보다 크다고(작다고) 결론 내고 비교를 종료합니다.
  3. 두 문자열의 첫 글자가 같으면 두 번째 글자를 같은 방식으로 비교합니다.
  4. 글자 간 비교가 끝날 때까지 이 과정을 반복합니다.
  5. 비교가 종료되었고 문자열의 길이도 같다면 두 문자열은 동일하다고 결론 냅니다. 비교가 종료되었지만 두 문자열의 길이가 다르면 길이가 긴 문자열이 더 크다고 결론 냅니다.

다른 형을 가진 값 간의 비교

비교하려는 값의 자료형이 다르면 자바스크립트는 이 값들을 숫자형으로 바꾼다.

alert( '2' > 1 ); // true, 문자열 '2'가 숫자 2로 변환된 후 비교가 진행됩니다.
alert( '01' == 1 ); // true, 문자열 '01'이 숫자 1로 변환된 후 비교가 진행됩니다.

불린값의 경우 true는 1, false는 0으로 변환된 후 비교가 이뤄진다.

alert( true == 1 ); // true
alert( false == 0 ); // true

일치 연산자

동등 연산자(equality operator) ==은 0과 false를 구별하지 못한다.

alert( 0 == false ); // true

피연산자가 빈 문자열일 때도 같은 문제가 발생하죠.

alert( '' == false ); // true

이런 문제는 동등 연산자 ==가 형이 다른 피연산자를 비교할 때 피연산자를 숫자형으로 바꾸기 때문에 발생한다. 빈 문자열과 false는 숫자형으로 변환하면 0이 된다.

그렇다면 0과 false는 어떻게 구별할 수 있을까?

일치 연산자(strict equality operator) ===를 사용하면 형 변환 없이 값을 비교할 수 있다.

일치 연산자는 엄격한(strict) 동등 연산자이다. 자료형의 동등 여부까지 검사하기 때문에, 피연산자 a와 b의 형이 다를 경우 a === b는 false를 즉시 반환한다.

alert( 0 === false ); // false, 피연산자의 형이 다르기 때문입니다.

일치 연산자 ===가 동등 연산자 ==의 엄격한 형태인 것처럼 “불일치” 연산자 !==는 부등 연산자 !=의 엄격한 형태이다.

일치 연산자는 동등 연산자보다 한 글자 더 길긴 하지만 비교 결과가 명확하기 때문에 에러가 발생할 확률을 줄여준다.

null vs 0

null과 0을 비교해보자

alert( null > 0 );  // (1) false
alert( null == 0 ); // (2) false
alert( null >= 0 ); // (3) true

위의 비교 결과는 논리에 맞지 않는다. (3)에서 null은 0보다 크거나 같다고 했기 때문에, (1)이나 (2) 중 하나는 참이어야 하는데 둘 다 거짓을 반환하고 있다.

이는 동등 연산자 ==와 기타 비교 연산자 > < >= <=의 동작 방식이 다르기 때문이다. (1)에서 null > 0이 거짓을, (3)에서 null >= 0이 참을 반환하는 이유는 (기타 비교 연산자의 동작 원리에 따라) null이 숫자형으로 변환돼 0이 되기 때문이다.

그런데 동등 연산자 ==는 피연산자가 undefined나 null일 때 형 변환을 하지 않는다. undefined와 null을 비교하는 경우에만 true를 반환하고, 그 이외의 경우(null이나 undefined를 다른 값과 비교할 때)는 무조건 false를 반환한다. 이런 이유 때문에 (2)는 거짓을 반환한다.

비교가 불가능한 undefined

undefined를 다른 값과 비교해서는 안 된다.

alert( undefined > 0 ); // false (1)
alert( undefined < 0 ); // false (2)
alert( undefined == 0 ); // false (3)

항상 false를 반환하고 있다.

이런 결과는 아래와 같은 이유 때문에 발생한다.

(1)과(2)에선 undefined가 NaN으로 변환되는데(숫자형으로의 변환), NaN이 피연산자인 경우 비교 연산자는 항상 false를 반환한다.
undefined는 null이나 undefined와 같고, 그 이외의 값과는 같지 않기 때문에 (3)은 false를 반환한다.

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

'if’문

예전 학교에서 java를 배울 때 배웠던 것이라 쉬웠다.
일단 if(...)문은 괄호 안에 들어가는 조건을 평가하는데, 그 결과가 true이면 코드 블록이 실행되는 구조이다.


let year = prompt('ECMAScript-2015 명세는 몇 년도에 출판되었을까요?', '');

if (year == 2015) alert( '정답입니다!' );

위 예시에선 조건(year == 2015)이 간단한 경우만 다뤘는데, 조건문은 더 복잡할 수도 있다.

조건이 true일 때 복수의 문을 실행하고 싶다거나 가독성을 위한다면 중괄호로 코드 블록을 감싸는 게 좋다고 생각한다.

if (year == 2015) {
  alert( "정답입니다!" );
  alert( "아주 똑똑하시네요!" );
}

불린(Boolean)형으로의 변환

if (…) 문은 괄호 안의 표현식을 평가하고 그 결과를 불린값으로 변환한다.

형 변환 챕터에서 배운 형 변환 규칙을 잠시 상기해보자

숫자 0, 빈 문자열"", null, undefined, NaN은 불린형으로 변환 시 모두 false가 된다. 이런 값들은 ‘falsy(거짓 같은)’ 값이라고 부른다.
이 외의 값은 불린형으로 변환시 true가 되므로 ‘truthy(참 같은)’ 값이라고 부른다.
이 규칙에 따르면 아래 예시의 코드 블록은 절대 실행되지 않는다.

if (0) { // 0은 falsy입니다.
  ...
}

아래 예시의 코드 블록은 항상 실행된다.

if (1) { // 1은 truthy입니다.
  ...
}

아래와 같이 평가를 통해 확정된 불린값을 if문에 전달할 수도 있다.

let cond = (year == 2015); // 동등 비교를 통해 true/false 여부를 결정합니다.

if (cond) {
  ...
}

'else’절

if문엔 else 절을 붙일 수 있다. else 뒤에 이어지는 코드 블록은 조건이 거짓일 때 실행된다.

let year = prompt('ECMAScript-2015 명세는 몇 년도에 출판되었을까요?', '');

if (year == 2015) {
  alert( '정답입니다!' );
} else {
  alert( '오답입니다!' ); // 2015 이외의 값을 입력한 경우
}

'else if’로 복수 조건 처리하기

유사하지만 약간씩 차이가 있는 조건 여러 개를 처리해야 할 때가 있는데 이때 else if를 사용할 수 있다.

let year = prompt('ECMAScript-2015 명세는 몇 년도에 출판되었을까요?', '');

if (year < 2015) {
  alert( '숫자를 좀 더 올려보세요.' );
} else if (year > 2015) {
  alert( '숫자를 좀 더 내려보세요.' );
} else {
  alert( '정답입니다!' );
}

위 예시에서, 자바스크립트는 조건 year < 2015를 먼저 확인한다. 이 조건이 거짓이라면 다음 조건 year > 2015를 확인한다. 이 조건 또한 거짓이라면 else 절 내의 alert를 실행한다.

else if 블록을 더 많이 붙이는 것도 가능하고 마지막에 붙는 else는 필수가 아닌 선택 사항이다.

조건부 연산자 ‘?’

조건에 따라 다른 값을 변수에 할당해줘야 할 때가 있다.

let accessAllowed;
let age = prompt('나이를 입력해 주세요.', '');

if (age > 18) {
  accessAllowed = true;
} else {
  accessAllowed = false;
}

alert(accessAllowed);
'물음표(question mark) 연산자’라고도 불리는 '조건부(conditional) 연산자’를 사용하면 위 예시를 더 짧고 간결하게 변형할 수 있다.

조건부 연산자는 물음표?로 표시한다. 피연산자가 세 개이기 때문에 조건부 연산자를 '삼항(ternary) 연산자’라고 부르는 사람도 있습니다. 참고로, 자바스크립트에서 피연산자가 3개나 받는 연산자는 조건부 연산자가 유일하다.

let result = condition ? value1 : value2;

평가 대상인 condition이 truthy라면 value1이, 그렇지 않으면 value2가 반환된다.

let accessAllowed = (age > 18) ? true : false;

age > 18 주위의 괄호는 생략 가능하다. 물음표 연산자는 우선순위가 낮으므로 비교 연산자 >가 실행되고 난 뒤에 실행된다.

아래 예시는 위 예시와 동일하게 동작하는 구조이다.

let accessAllowed = age > 18 ? true : false;

다중 ‘?’

물음표 연산자?를 여러 개 연결하면 복수의 조건을 처리할 수 있다.

let age = prompt('나이를 입력해주세요.', 18);

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

alert( message );

물음표 연산자를 이런 방식으로 쓰는 걸 처음 본 사람이라면 이 코드가 어떻게 동작하는지 파악하기 힘들 수 있다. 그러나 주의를 집중하고 보면, 단순히 여러 조건을 나열한 코드임에 불과하다는 것을 알 수 있다.

첫 번째 물음표에선 조건문 age < 3을 검사한다.
그 결과가 참이면 '아기야 안녕?'를 반환한다. 그렇지 않다면 첫 번째 콜론 ":"에 이어지는 조건문 age < 18을 검사한다.
그 결과가 참이면 '안녕!'를 반환한다. 그렇지 않다면 다음 콜론 ":"에 이어지는 조건문 age < 100을 검사한다.
그 결과가 참이면 '환영합니다!'를 반환한다. 그렇지 않다면 마지막 콜론 ":" 이후의 표현식인 '나이가 아주 많으시거나, 나이가 아닌 값을 입력 하셨군요!'를 반환한다.
if..else를 사용하면 위 예시를 아래와 같이 변형할 수 있다.

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

마치며

벌써 3일 째도 끝나가게 됐는데 뭔가 간단하다고 아직 초반이라 생각했던 주제가 생각보다 예외같은 경우의 수들이 많아 당황했는데 나중에 프로그래밍을 할 때 그 하나로 프로그램이 무너질 일이 없도록 기초를 탄탄히 쌓아야겠다.

또한 아직은 내용의 출처 사이트에서 혼자 공부를 하고 블로그에 깜지식?으로 기록을 남기며 복습을 하는 형식으로 진행중이다.

하지만 깜지식 보다는 좀 더 내 주관과 내 이해가 섞인 복습과 블로그 글 작성이 될 수 있도록 더 노력해야겠다.




출처

내용 : https://ko.javascript.info/intro
썸네일 제작 : https://www.canva.com/

profile
https://github.com/WonseoYang

0개의 댓글