- Published on
모던 자바스크립트 Deep Dive 복습 2
- Authors

- Name
- Byeong Jun An
표현식과 문
용어를 정확히 이해하고 설명하기 위해 해당 글을 작성하고자 한다.
용어
값 : 값은 식(표현식 expression)이 평가되어 생성된 결과물을 말한다.
평가 : 평가란 식을 해석해서 값을 생성하거나 참조하는 것을 말한다.
리터럴 : 사람이 이해 할 수 있는 문자 또는 약속된 기호를 사용하여 값을 생성하기 위해 미리 약속한 표기 법
표현식 : 값을 계산하거나 평가하는 목적을 가진 문(statement)
문 : 프로그램을 실행할 수 있는 최소단위의 명령어로, 특정 작업을 수행하거나 프로그램의 흐름을 제어한다. 문은 여러 토큰으로 구성되어 있다.
토큰: 문법적으로 더 이상 나눌 수 없는 기본 요소 예를들어 키워드(let, const), 식별자(x, y), 연산자(+, -), 리터럴(10, "Hello"), 세미콜론(;) 등이 있다.
표현식인 문과 표현식이 아닌 문
표현식이 되려면 값으로 평가될 수 있어야 한다. 따라서 표현식인 문은 값으로 평가 될 수 있는 문을 말하며, 표현식이 아닌 문은 값으로 평가 할 수 없는 문을 말한다. 예를들어
var x // 변수 선언문
는 값으로 평가 될 수 없으므로 표현식이 아닌 문이고
x = 1 + 2
는 3이라는 평가될 수 있는 표현식인 문이다.
사실 표현식인 문과 표현식이 아닌 문을 가장 쉽게 구별할 수 있는 방법이 있는데 그것은 변수에 할당해 보는 것이다.
위에서 얘기한 var x를 다른 변수 선언문에 할당해 보면
var foo = var x;
// console.log를 찍어보면 문법 오류(SyntaxError)가 나올 것이다.
와 같은 형태로 나타나는데 할당해 봤을 때, 표현식이 아닌 문이라면 위 예시처럼 오류가 나서 사용 할 수 없을것이고
만약 표현식인 문이라면
var foo = (x = 100)
// console.log를 찍어보면 foo와 x에 100이라는 값이 들어가 있는 걸 알 수 있다.
과 같이 실행해보면 정상작동 하는 걸 알 수 있다.
완료 값
표현식이 아닌 문을 실행한 후 반환되는 값을 말한다. 예를들어 크롬 개발자 도구에서 표현식이 아닌 문(값을 반환하지 않는 문)을 실행하면 언제나 undefined를 출력한다. 이는 반환하는 값이 없다는 뜻이지 undefined 라는 값 자체를 반환한다고 착각하면 안된다. 또한 완료 값은 자바스크립트 엔진이 문을 실행한 후 내부적으로 사용하는 값으로, 개발자가 직접 이 값을 변수에 할당하거나 참조할 수는 없다.
Q&A
Q. 값과 리터럴의 차이는 뭔가요?
A: 리터럴은 코드에서 직접적으로 표현된 고정된 값이고, 값은 변수에 저장되거나 연산에 사용되는 데이터를 의미합니다.
Q. 값과 표현식의 관계를 설명하세요
A: 값은 표현식에서 생성된 결과물이고 표현식은 값을 계산하거나 표현하기 위해 사용하는 문입니다. 따라서 표현식이 값을 항상 생성하는 관계라고 볼 수 있습니다.
Q. 표현식인 문과 표현식이아닌 문의 차이는?
A: 값을 평가할 수 있냐 없냐 입니다. 예를 들어 표현식인 문은 10 + 20 과 같이 값을 평가 할 수 있고 변수 선언문이나 조건문 그 자체는 값으로 평가 될 수 없기때문에 표현식이 아닌 문입니다.
Q. 완료 값이란?
A: 표현식이 아닌 문을 실행한 후 반환되는 값을 말한다.
데이터 타입
데이터 타입은 값의 종류를 말한다. Bigint를 포함해 현재는 총 8개의 데이터 타입을 갖고 있는데 중요한 부분만 짚고 넘어가려고 한다.
타입 종류 및 특징
1. 숫자 타입
자바스크립트는 모든 수를 실수로 처리하며, 이는 정수로 표시 된다 해도 사실은 실수라는 것을 의미하며 정수로 표시되는 수끼리 나누더라도 실수가 나올 수 있다는 걸 의미한다. 숫자타입으로 Infinity, -Infinity, NaN 이라는 값도 표현할 수 있는데 각각 양의 무한대, 음의 무한대, 산술 연산 불가를 나타낸다.
2. 문자열 타입
텍스트 데이터를 나타내는 데 사용하며 작은 따옴표(''), 큰따옴표(""), 백틱(``)으로 텍스트를 감싼다. 문자열은 문자열 연산자인 +를 사용해 연결할 수 있는데 +연산자는 피연산자 중 하나 이상이 문자열인 경우에 문자열 연결 연산자로 동작한다.
3. 불리언 타입
불리언 타입의 값은 논리적 참, 거짓을 나타내는 true와 false를 말하는데 불리언 타입의 값은 조건에 의해 프로그램 흐름을 제어하는 조건문에서 자주 사용한다.
4. undefined 타입
undefined는 개발자가 의도적으로 할당하기 위한 값이 아니라 변수를 참조했을 때 초기화가 안됐다면 이를 알리는 의도로 만들어진 것이다. 좀 더 자세히 알아보기 위해 undefined를 직역해보면 '정의되지 않은' 이라는 뜻을 가진다는 것을 알 수 있다.
여기서 자바스크립트에서의 정의와 선언의 차이를 알면 좋은데 일단 선언은 이전에 없던 요소(주로 식별자)를 이 시간 이후로 요소가 있다고 자바스크립트 엔진에게 알리는 것을 말하고 정의는 그 요소에 실제 값을 할당하는 것을 말한다.
예를 들어
var x
는 자바스크립트 엔진에게 x라는 변수가 존재한다고 알리는 선언이고
var x = 10
은 자바스크립트 엔진에게 x 라는 변수에 10이라는 값을 할당하라고 지시하는 정의이다.
따라서 정의는 단순히 변수나 함수의 존재를 알리는 선언과 달리, 그 변수나 함수에 구체적인 값을 제공하는 것을 말하고 undefined를 반환한다는 건 그 변수나 함수에 구체적인 값을 제공하지 않았다는 뜻이다.
var x
console.log(x) // undefined
function myFunction() {
// 아무 값도 반환하지 않음
}
console.log(myFunction()) // undefined
5. null 타입
null은 프로그래밍 언어에서 변수에 값이 없다는 것을 의도적으로 명시할 때 사용한다. 특징으로는 변수에 null을 할당하는 것은 이전에 할당되어 있던 값에 대한 참조를 명시적으로 제거하는 것을 의미한다. 이렇게 되면 가비지 컬렉터를 통해 메모리를 확보 할 수 있게 된다.
이것 외에도 함수가 유효한 값을 반환할 수 없는 경우 null을 반환하기도 한다.
...
<body>
<script>
var element = document.querySelector('.element');
//HTML 요소에 element라는 클래스가 없다면 null을 반환한다.
console.log(element);
</script>
</body>
...
6. 심벌 타입
심벌은 변경 불가능한 원시 타입의 값으로 다른 값과 중복되지 않는 유일무이한 값이다. 주로 객체의 유일한 프로퍼티 키를 만들기 위해 사용한다.
7. 객체 타입
객체 타입은 여러 개의 값을 하나의 값으로 쓰기 위해 사용된다.
8. Bigint 타입
ECMAScript2020(ES11)에서 추가된 데이터 타입으로 숫자값을 안정적으로 나타낼 수 있는 최대치인 -1 보다 큰 정수를 표현할 수 있는 새로운 원시값이다. Bigint 값은 정수 리터럴 뒤에 n을 붙이거나 (10n) Bigint 함수를 호출해서 생성할 수 있다 (Bigint(10))
데이터 타입의 필요성
컴퓨터는 한번에 읽어 들여야 할 메모리 셀의 크기를 어떻게 알 수 있을까? 만약 변수에 숫자 타입의 값이 할당되어 있다면 자바스크립트 엔진은 변수가 아닌 변수에 들어있는 값을 보고 숫자 타입으로 인식한다. 숫자 타입은 8바이트 단위로 저장되는데 엔진이 해당 변수를 참조하면 8바이트 단위로 메모리 공간에 저장된 값을 읽어들인다. 이를 보면 데이터 타입이 필요한 이유를 알 수 있는데
데이터 타입이 필요한 이유는
- 값을 저장할 때 확보해야 할 메모리 공간의 크기를 결정하기 위해
- 값을 참조할 때 얼만큼의 메모리 공간의 크기를 가져와야 할지 알기 위해
- 읽어 들인 2진수를 어떻게 해석할지 결정하기 위해
이다.
3번의 경우는 예를 들면 숫자형 1과 문자형 "1"을 구분해야 하는데 이것 때문에 데이터 타입이 필요함을 알 수 있다.
Q&A
Q. 동적 타이핑이란?
A: 변수의 데이터 타입이 런타임에 결정되고 변수에 할당된 값에 따라 자동으로 타입이 결정되고 변경되는 것
Q. 동적 타입 언어의 장단점은?
A: 유연성이 높지만 신뢰성이 떨어진다. 유연성이 높다는건 타입이 할당 된 값에 따라 자동으로 결정되기 때문이고 신뢰성이 떨어진다는 건 값에 따라 타입이 정해지기 때문에 개발자가 예측하기 어려울 수 있고 암묵적으로 타입이 변경 되기 때문에 숫자타입일거라 예상했지만 다른 타입이 나올 수 있어 신뢰성이 떨어진다고 봄
Q. 동적 타입 언어에서 변수를 사용할 때 주의사항?
A:
- 변수는 꼭 필요할 때만 사용해야 한다.
- 전역변수를 최대한 사용하지 않도록 한다.
- 재할당을 최대한 안하도록 해야한다.
- 명확한 변수 이름을 사용해야 한다.
- 변수의 스코프를 최대한 좁게 설정한다.
연산자
연산자란 하나 이상의 표현식을 대상으로 연산을 수행하여 값을 반환하는 기호나 키워드를 말한다.
연산자의 종류 및 특징
산술 연산자
산술 연산자는 피연산자의 개수에 따라 이항 산술 연산자와 단항 산술 연산자로 구분 할 수 있다.
이항 산술 연산자는 2개의 피연산자를 산술 연산하여 숫자 값을 만드는데 모든 이항 산술 연산자는 피연산자의 값을 변경하는 부수 효과가 없다. 즉, 어떤 산술 연산을 해도 피연산자의 값이 바뀌는 경우는 없고 새로운 값을 만든다. 대표적으로 덧셈(+), 뺄셈(-), 곱셈(*), 나눗셈(/), 나머지(%), 거듭제곱(**) 등이 있다.
단항 산술 연산자는 1개의 피연산자를 산술 연산하여 숫자 값을 만드는데 증가/감소(++/--) 연산자는 피연산자의 값을 변경하는 부수 효과가 있다. 즉, 증가/감소 연산을 하면 피연산자의 값을 변경하는 암묵적 할당이 이뤄진다.
var x = 1
// ++ 연산자는 피연산자의 값을 변경하는 암묵적 할당이 이뤄진다.
x++ // x = x+1;
console.log(x) // 2
증가/감소 연산자는 위치에 따라 의미가 달라지는데 피연산자 앞에 위치한 전위 증가/감소 연산자는 먼저 피연산자의 값을 증가/감소 시킨 다음 다른 연산을 수행한다. 피연산자 뒤에 위치한 후위 증가/감소 연산자는 먼저 다른 연산을 수행한 후 피연산자의 값을 증가시킨다.
var x = 5,
result
//선 할당 후 증가
result = x++
console.log(result, x) // 5 6
//선 증가 후 할당
result = ++x
console.log(result, x) // 7 7
+단항 연산자는 숫자 타입이 아닌 피연산자에 +단항 연산자를 사용하면 숫자타입으로 변환하여 반환한다. 이때 피연산자를 변경하는 것은 아니고 숫자 타입으로 변환한 값을 생성해서 반환한다. 따라서 부수효과는 없다.
+연산자는 피연산자 중 하나 이상이 문자열인 경우 문자열 연결 연산자로 동작한다. 그 외에는 산술 연산자로 동작한다.
할당 연산자
할당 연산자는 우항에 있는 피연산자의 평가 결과를 좌항에 있는 변수에 할당한다. 할당 연산자는 좌항의 변수에 값을 할당하므로 변수 값이 변하는 부수 효과가 있다. 대표적으로 기본 할당(=), 더하기 할당(+=), 빼기 할당(-=) 등이 있다.
비교 연산자
두 값을 비교하여 참(true) 또는 거짓(false)을 반환하는 연산자로, 동등(==), 일치(===), 크다(>), 작다(<)가 있다. 일치 비교 연산자에서 헷갈리기 쉬운것이 있는데 그건 NaN은 자신과 일치하지 않는 유일한 값이라는 점이다. 따라서 숫자가 NaN인지 조사하려면 빌트인 함수 Number.isNaN을 사용해야 한다.
삼항 조건 연산자
삼항 조건 연산자는 조건식의 평가 결과에 따라 두 번째 피연산자나 세 번째 피연산자로 반환할 값을 결정한다. 따라서 삼항 조건 연산자는 값으로 평가될 수 있기 때문에 표현식이라고 할 수 있다.
그 외 연산자
논리 연산자(||, &&, !), 쉼표 연산자(,), 그룹 연산자 (()), 옵셔널 체이닝 연산자(?.) null 병합 연산자(??), typeof 연산자( 타입이 뭔지 문자열로 반환) delete(프로퍼티 삭제), new(생성자 함수를 호출할 때 사용하여 인스턴스를 생성), instanceof(인스턴스인지 판별), in(프로퍼티 존재 확인) 등이 있다.