JavaScript
20210703 JavaSciprt DeepDive 01 : 변수, 표현식과 문, 데이터 타입, 연산자, 제어문
JavaScript Deep Dive 01
용어 및 중요사항 정리
변수
변수
: 확보한 메모리 공간 자체 or 메모리 공간 식별자
식별자
: 어떤 값을 구별해서 식별할 수 있는 고유한 이름(식별자는 값이 아니라, 메모리 주소를 기억함으로서 메모리 주소에 붙인 이름 역할을 함)
변수선언
: 변수를 사용하기 위한 메모리 공간 확보와 변수 이름과 확보된 메모리 공간의 주소 연결 (값 저장 준비, var, let, const)- 값 할당 없이 변수선언만 되어도, undefined가 기본으로 할당 되어 초기화 됨
변수 호이스팅
: 변수 선언문이 코드 작성 맨위로 올라 간듯이 동작하는 특징- 변수 선언이 런타임 전에 실행되기 때문 (var, let, const, function, function*, class 키워드로 선언하는 모든 식별자)
값의 할당
: 우변의 값을 좌변의 변수에 할당하는 것 (변수 선언과 값의 할당은 2개의 문으로 나뉨)- 변수 선언은 런타임 전에 실행되고 , 값 할당은 런타임때 실행됨
- 값이 할당 되는 경우 기존에 메모리에 저장된 값에 덮어 쓰는 것이 아닌 새로운 공간에 값을 저장하고 해당 공간을 가르키도록 변경됨
console.log(a); // undefined <- 변수 선언 되면서 아직 명시적으로 값이 할당 되지 않았기 때문에 (기본적으로 undefined 가 할당 됨으로) var a = "Hi!"; // var a -> 런타임 -> = 'Hi!' console.log(a); // Hi!
값의 재할당
: 이미 값이 할당 되어 있는 변수에 새로운 값을 또다시 할당하는 것- 재할당이 가능해서 변수는 변수다.
- 변수에 저장된 값을 변경할 수 없으면 상수(constant) (const 키워드가 상수임)
가비지 콜렉터
: 앱이 할당한 메모리 공간을 주기적으로 검사하여 더이상 사용하지 않는 메모리를 해제하는 것- 변수의 값이 재할당 되면서 가르키는 메모리가 변경되고, 어떠한 변수도 해당 값이 저장된 공간을 가르키지 않아 사용하지 않는 값은 가비지 콜렉터에 의해 메모리에서 자동 해제됨
언매니저드& 매니지드 언어
: 언어가 메모리 제어를 자동으로 할수 있는지 없는지에 따라 달라짐- Javascript는 매니지드 언어 임(개발자가 제어 불가, 언어가 자동으로 제어)
예약어
: 프로그래밍 언어에서 사용되고 있거나, 사용될 예정인 단어들을 말함
식별자 명명 규칙
:- 사용할 수 있는 문자: 알파벳, 숫자, 언더스코어(_), 달러기호($)
- 첫글자: 영어, _, $
- 예약어는 안됨
표현식과 문
네이밍컨벤션
: 식별자 구분 명명 규칙 (camelCase, snake_case, PascalCase, typeHungarianCase)
값(value)
: 표현식(식)이 평가되어 생성된 결과, 변수에 할당되는 것
평가(evaluate)
: 식 해석(계산)을 통한 값 생성 또는 참조
리터럴(literal)
: 값을 생성하는 방법으로 사람이 이해할 수 있는 문자 or 약속된 기호를 사용해 값을 생성하는 표기법(notation)- 런타임에 리터럴을 평가해 값을 생성
- 정수, 부동소수점, 2진수, 8진수, 16진수, 문자열, 불리언, null, undefined, 객체, 배열, 함수, 정규 표현식
표현식(expression)
: 값으로 평가될 수 있는 문(statement)- 표현식이 평가되어 새로운 값을 생성 또는 기존 값을 참조함 (리터럴 포함)
- 기본적인 리터럴, 연산자, 변수 식별자 참조(이미 선언이 된 변수 식별자), 함수/메서드 호출
- 표현식은 값처럼 활용할 수 있어서 다르 표현식의 일부가 되어 새로운 값을 만들어 낼 수 있음
- 표현식은 문의 일부일 수도 있고 그자체로 문이 될 수도 있음
const x = 1 + 2; // x는 값으로 활용 될수 있음 x + 3; // 6 <- 표현식이 다른표현식의 일부로서 작용하여 새로운 값을 생성
동치(equivalent)
: 표현식과 표현식이 평가된 값이 동등한 관계를 일컫는 말
문(statement)
: 프로그램을 구성하는 기본단위, 최소 실행 단위 (문의 집합 -(프로그래밍)-> 프로그램)- 문은 토큰으로 구성됨
- 변수 선언문
- 할당문
- 함수 선언문
- 조건문
- 반복문
- 문이 끝나면 세미콜론(;)을 작성해서 종료를 나타냄
- 단, 블록 형태({})의 문은 붙지 않음/ 함수 선언문, 조건문, 반복문/ 블록이 종결성을 갖기 때문
- 표현식인 문(실행O, 평가O) vs 표현식이 아닌 문(실행O, 평가X) -> 평가, 실행 차이
var x; // 실행은 되지만 평가는 안됨 -> 표현식이 아닌 문 x = 100; // 실행도 되고, 평가도 됨 -> 표현식인 문
- 문은 토큰으로 구성됨
토큰(token)
: 문법적으로 더이상 나눌 수 없는 코드 (키워드, 식별자, 연산자, 리터럴, 세미콜론, 마침표 등)
데이터 타입
데이터 타입(data type, type)
:- 원시: number, string, boolean, undefined, null, symbol
- 객체: 객체, 함수, 배열 등
숫자 타입(Number Type)
: 배정밀도 64비트 부동소수점 형식 -> 실수 (정수만 표현X)- 모두 2진수로 저장 -> 값 참조시 모두 10진수로 해석됨
- 특별한 값: Infinity, -Infinity, NaN(Not a Number)
문자열 타입(String)
: JS 일반적인 표기법은 작은 따옴표('')/ 그외 ("", ``)- 키워드 또는 식별자와 구분하기 위해서 따옴표 사용
- 원시 타입(Primitive), 변경 불가능한 값(Immutable value)
템플릿 리터럴(template literal)
: 문자열 처리 기능 제공 -> 멀티라인 문자열, 표현식 삽입, 태그드 템플릿- 멀티라인 문자열 : 문자열 내에서의 줄바꿈 개행을 허용하여 인식함 (일반 문자열인 경우 개행 인식을 위해 이스케이프 시퀸스를 사용함)
- 표현식 삽입 : 기존의 문자열 조합을 위해 문자열 연산자를 사용했었는데 표현식 삽입을 통해 간단히 문자열을 삽입 가능 (`삽입 당할 내용 ${문자열에 추가시킬 표현식} 삽입 당할 내용`)
- 문자열 연산자 (+) : 피연산자 중에 하나 이상이 문자열인 경우 문자열 연산자로 동작 (그외엔 덧셈 연산자로 작동)
라인피드(LF) vs 캐리지 리턴(CR)
- Carriage Return (\r) : 커서를 처음으로 이동
- Line Feed(\n) : 커서를 다음 행으로 아래로 내림
- 운영체제 마다 채택한 개행 정책이 다름(macOS: LF, windows: CR+LF) -> 텍스트 에디터는 운영체제에 맞게 개행문자를 자동으로 변환해 줌
- JavaScript에서는 보통 피드(\n)를 개행으로 사용
불리언 타입
: 논리적인 참, 거짓 (true, false)로서 조건문에 자주 사용
undefined 타입
: 자바스크립트 엔진이 변수를 초기화 할때 사용하는 값 (개발자가 어떤 값을 초기화 시킨적이 없다는 뜻), 개발자가 의도적으로 값이 없다고 명시하고 싶을 때는 null을 사용
선언(declaration) vs 정의(definition)
: C에서는 식별자에 메모리 주소가 연결(할당)되었는가로 선언과 정의를 나눔 (연결되면 정의, 아니면 선언)- 정의 : 어떤 대상을 명확하게 규정, 식별자에 메모리 주소가 연결(할당)
- 선언 : 단순 컴파일러에 식별자의 존재를 알림,식별자에 메모리 주소가 연결(할당) 되지 않음
- JavaScript의 경우 변수선언시 암묵적으로 정의가 이루어 지기 때문에 선언과 정의 구분이 모호함
- undefined 라는 값이 정의 되었지만, undefined는 정의 되지 않은 임을 뜻함
- 변수는 선언, 함수는 정의
null 타입
: null은 변수에 값이 없다는 것을 의도적으로 명시 할때 사용- null 을 변수에 할당하는 것은 이전 할당되어 있던 값에 대한 참조를 명시적으로 제거를 의미
- JavaScript는 이렇게 null을 명시하면 카비지 콜렉션을 수행하여 아무도 참조하지 않는 이전 값을 차지하는 메모리 공간을 삭제 할 것임
- 그래서, 의도적으로 어떤 값이 없게 되거나 반환할게 없는 경우 undefined이 아니라 null을 사용함
심벌(symbol) 타입
: 변경 불가능한 원시 타입의 값, 다른 값과 중복 되지 않는 유일한 값- symbol은 함수를 호출해 생성함 (나머지 원시 타입은 리터럴로 생성)
객체 타입
: 원시 타입과 반대되는 값들(자바스크립트를 이루고 있는 거의 모든 것이 객체임)
저장 단위
:- 1비트
- 1바이트 = 8비트
- 1킬로바이트 = 1000바이트 = 8000비트
- 1메가바이트 = 10^6바이트 = 8 * 10^6비트
- 1기가바이트 = 10^9바이트
- 1테라바이트 = 10^12바이트
- 예시) javascript number 타입의 값 경우 64비트 부동소수점 -> 메모리 저장시 8바이트 공간 필요
메모리 저장과 참조, 해석
- 심벌 테이블 : 식별자를 key로하여 값의 메모리 주소, 데이터 타입, 스코프 등을 관리
- 식별자 - 심벌테이블 - 메모리
- 저장 : 코드 실행 -> 해당값의 타입에 맞게 메모리 공간 확보 -> 2진수로 해당 메모리 공간에 저장
- 참조 : 코드 실행 -> 식별자로 메모리 공간 주소로 찾아감 -> 타입으로 한번에 읽어 들여야할 메모리 공간을 알아보고 읽음
- 해석 : 타입을 보고 해당 메모리에 있는 2진수를 어떻게 해석해야 할지 결정해서 해석함
- 심벌 테이블 : 식별자를 key로하여 값의 메모리 주소, 데이터 타입, 스코프 등을 관리
데이터 타입이 필요한 이유
- 값 저장시 메모리 공간 크기 결정
- 값 참조시 한번에 읽어 들여야 할 메모리 공간 크기 결정
- 메모리에서 읽어 들인 2진수를 어떻게 해석할지 결정하기 위해
정적타입 언어
:- 변수 선언시 변수에 할당할 수 있는 값의 타입을 사전에 선언하는 언어들(명시적 타입 선언)
- C, C++, 자바, 코틀린, 고, 하스켈, 러스트, 스칼라
- 컴파일 시점에 타입 체크를 함 -> 프로그램 실행 할지 말지 결정
- 변수 선언시 변수에 할당할 수 있는 값의 타입을 사전에 선언하는 언어들(명시적 타입 선언)
동적타입 언어
: javascript와 같이 동적타이핑이 가능한 언어- python, ruby, lisp, perl 등
- 유연성은 높지만 신뢰성이 떨어짐
타입추론(type inference)
: javascript 처럼 동적타입 언어의 경우 변수 선언이 아닌 값 할당에 의해 타입이 결정되는 것 (즉, 값에 의해 변수의 타입이 결정)동적타이핑(dynamic typing)
: 값이 재할당 될때 마다 타입이 언제든지 동적으로 변하는 특징
트레이드 오프(trade-off)
: 하나를 개선하면 다른 하나가 희생되는 모순적 관계은 탄환(silver bullet)
: 고질적인 문제를 단번에 해결할 수 있는 명쾌한 해결책 (사실, 은탄환은 없음)
변수 사용 주의 사항
- 필요한 만큼 최소한으로 유지
- 변수의 유효 범위(스코프)는 최대한 좁게 만들자
- 전역변수 최소화
- 변수보다는 상수를 사용하자
- 변수 이름(식별자)를 목적, 의미 파악할 수 있게 네이밍 하자
연산자
연산자 표현식
: 연산자와 피연산자의 조합으로 이루어진 표현식피연산자(operand)
: 연산의 대상으로 표현식 이여야 함연산자(Operator)
: 하나 이상의 표현식을 대상으로 산술, 할당, 비교, 논리, 타입, 지수 연산 등을 수행하여 하나의 값을 만드는 토큰
산술연산자
: 피연산자를 가지고 수학적 계산을 수행하여 새로운 숫자 값을 만듦 (연산 불가시 NaN 반환)부수효과(side Effect)
: 피연산자의 값을 변경하는 것(변수가 가진 값 원본을 변경하는 것)이항(binary) 산술 연산자
: 2개의 피연산자를 산술 연산하여 숫자값을 만듦- 부수효과X -> 언제나 새로운 값을 만듦
- +, -, *, /, %, //
단항(unary) 산술 연산자
: 1개의 피연산자를 산술 연산하여 숫자 값을 만듦+
: 어떠한 효과도 없음 / 부수 효과X- 단지, 숫자타입이 아닌 피연산자에 붙여 사용시 값을 숫자타입으로 변경하여 새로운 숫자 값을 만듦
- '1' -> 1, true -> 1, false -> 0, 'string' -> NaN
-
: 양수를 음수로, 음수롤 양수로 반전한 값을 반환 / 부수 효과X- 역시, 값을 숫자타입으로 변경시키고 부호도 반전시킴
++
,--
: 증가, 감소/ 부수 효과 O(암묵적 할당이 있어 원본에 변경을 줌)- 전위 증감연산자: 먼저 피연산자 값을 증가/감소 후 다른 연산을 수행
- 후위 증감연산자: 먼저 다른 연산을 수행 후, 피연산자의 값을 증감
// '=' 을 기준으로 생각 변수와 바로 만나면 할당 먼저, 증감연산자를 바로 만나면 증감 먼저 let x = 5, result; result = x++; // result에 선할당 후 x증가 console.log(result, x); // 5, 6 result = ++x; // x 먼저 증가 후 result에 할당 console.log(result, x); // (7, 7)
문자열 연결 연산자('+')
: 피연산자 중 하나 이상이 문자열인 경우 문자열 연결 연산자로 동작
암묵적 타입 변환(implicit coercion), 타입 강제 변환(type coercion)
- 자바 스크립트엔진이 암묵적으로 타입을 강제로 변환하는 것
- 단항 산술연산자 +, - 를 통해서 숫자 타입으로 변환
- 자바 스크립트엔진이 암묵적으로 타입을 강제로 변환하는 것
할당 연산자
: 우항에 있는 피연산자의 평가 결과를 좌항에 있는 변수에 할당 (변수 값이 변하는 부수 효과가 있음)- =, +=, -=, *=, /=, %=
- 모두 부수 효과가 있음
- 숫자 뿐만아니라 문자연결시에도 사용 가능
할당문
: 표현식인 문(할당된 값으로 평가됨)연쇄할당
:- 여러 변수에 동일한 값을 연쇄 할당 가능 (a = b = c = 0;)
- 표현식이므로 연쇄적으로 사용해서 더큰 표현식으로 만들 수 있음
비교 연산자
- 좌항, 우항의 피연산자 비교한 결과를 불리언 값 반환
동등 vs 일치 비교 연산자
: 동등비교(==), 일치비교(===), 부동등비교(!=), 불일치비교(!==)- 동등비교의 경우 비교시 피연산자를 먼저 암묵적 타입 변환하여 타입을 일치시킨 후 비교함 -> 예측 어려움
- 일치비교의 경우 좌우 타입도 같고, 값도 같아야 true를 반환
- 단, NaN === NaN 은 유일하게 false임 (NaN 확인은 isNaN함수 사용)
- -0, 0은 같음
Object.is(A,B)
: A, B를 예측 가능한 정확한 비교 결과를 반환 (-0,0 / NaN 문제 해결)
대소관계 비교 연산자
: >, <, <=, >= -> true or false
삼항조건 연산자
: 조건에 따른 반환할 값 결정(부수 효과 X)- 조건식 ? true시 반환 값 : false시 반환값
- 조건식의 결과가 불리언이 아니면 불리언으로 암묵적 타입 변환 일어남
- 삼항조건 연산자 vs 조건문
- 삼항조건 연산자는 표현식으로 값처럼 사용가능
- 조건문(if...else)은 값처럼 사용 불가
- 어떤 값을 결정하는 경우 -> 삼항 조건 연산자
- 수행해야할 문이 여러개라면 -> if ...else 문
논리 연산자
- 좌우항 논리연산
- 논리합(||), 논리곱(&&), 논리부정(!) / 부수효과X
- ||, &&은 언제나 불리언 값을 반환 하지 X : 2개의 피연산자 중 어느 한쪽으로 평가
- 논리 부정(!) 연산자 언제나 불리언 값 반환
- 피연산자가 불리언 값이 아니면 불리언 타입으로 암묵적 변환
드 모르간의 법칙
!(x || y) === (!x && !y); !(x && y) === (!x || !y);
쉼표연산자
- 왼쪽의 피연산자 부터 차례대로 피연산자 평가 후 마지막 피연산자의 평가 결과를 return
그룹연산자
- 소괄호로 피연산자를 감싸 그룹 연산자를 활용하면, 그룹 연산자의 우선순위를 높임
typeof 연산자
: 피연산자의 데이터 타입을 문자열로 반환- string, number, boolean, undefined, symbol, object, function
- '' -> string , 1 -> number, NaN -> number, true -> boolean, Symbol() -> symbol
- undefined -> undefined, function() {} -> function
- null, [], {}, new Date(), /test/gi -> object
- null 타입 확인은 일치 연산자로 확인할 것! (typeof foo === null)
- 선언하지 않은 식별자의 type은 undefined 반환
지수 연산자
- 좌항을 밑(base), 우항을 지수(exponent)로 거듭 제곱하여 숫자값 반환
- 2 * 2; -> 4, 2 ** 2 *\ 2; -> 16
- 음수를 밑으로 사용시 괄호로 묶어야 함
- 할당 연산자와 같이 사용 가능 (**=)
- 지수 연산자는 이항 연산자 중에 우선순위가 가장 높음
기타 연산자
옵셔널 체이닝 연산자(?.)
null 병합 연산자(??)
프로퍼티 삭제(delete)
new 연산자(new)
:생성자 함수 호출시 사용하여 인스턴스 생성instanceof 연산자(instanceof)
: 좌변의 객체가 우변의 생성자 함수와 연결된 인스턴스인지 판별in연산자 (in)
: 프로퍼티 존재 확인
부수효과 있는 연산자
- 할당 연산자(=), 증감연산자(++/--), delete연산자 (원본 지장O, 다른 코드에 영향을 줌)
- 위에 외에는 부수 효과 없음 (원본 지장X, 다른 코드에 영향 X)
연산자 우선순위
- 연산자 우선순위가 높을 수록 먼저 실행됨
- ( ) 그룹 연산자
- new(매개변수 존재), .,[](프로퍼티 접근), ()(함수호출), ?.(옵셔널 체이닝)
- new(매개변수 미존재)
- 후위 증감연산자 (x++, x--)
- !x(부정), +x, -x(단항 산술), ++x, --x(전위 증감연산자), typeof, delete
- **(지수 연산자)
- *, /, % (이항 연산자)
- +, - (이항 연산자)
- <, >, <=, >=(대소 비교 연산자), in, instanceof
- ==, !=, ===,!== (동등, 일치 비교 연산자)
- ?? (null 병합 연산자)
- && (논리 곱)
- || (논리 합)
- ? A : B (삼항조건 연산자)
- =, +=, -=, ... (할당 연산자)
- , (쉼표 연산자)
- 연산자 우선순위가 높을 수록 먼저 실행됨
연산자 결합 순서
: 연산자의 좌,우 어느쪽부터 평가를 수행할 것인지- 좌->우 : +,-,/,%, <, >, <=, >=, &&, ||, ., [], (), ??, ?., in, instanceof
- 우->좌 : ++, --, 할당 연산자(=, +=, -=, ...), !x, +x, -x, ++x, --x, typeof, delete, ?a:b
제어문
제어문
: 코드의 실행 흐름을 인위적으로 제어 할수 있음 (조건문, 반복문)
블록문
: 0개 이상의 문을 중괄호({})로 묶은 것(코드블록, 블록)- JS는 하나의 실행 단위로 취급함
- 보통은 제어문, 함수 정의시 사용함
조건문
: 주어진 조건의 평가 결과에 따라 블록문의 실행을 결정- 조건식은 불리언 값으로 평가될 수있는 표현식
if..else문
- 조건식의 평가 결과가 true -> if문의 코드 블럭 실행
- 조건식의 평가 결과가 false -> else 문의 코드 블럭 실행
- 조건식은 불리언 값으로 평가 되어야 함
- 추가 조건은 else if문 활용
- 코드 블럭내의 문이 1개면 중괄호 생략 가능
- 삼항 조건 연산자로 변경 가능 (삼항 조건 연산자의 경우 자신을 구성하게 중복하여 사용이 가능함)
- 변수에 할당 하는 경우 삼항 조건 연산자를 활용하는게 좋고, 실행 내용이 여러 줄이라면 if...else문을 사용하는 것이 좋음
switch문
: 주어진 표현식을 가진 case문으로 실행 흐름을 옮김- switch문의 조건식은 보통 문자열이나 숫자 값으로 사용함 (다양한 상황시 실행될 코드 블록 결정)
case문
: 특정 상황의 표현식을 지정하고 콜론을 쓰고, 해당 실행 문들을 위치시킴default문
: case 문에 걸리는게 없는 경우 실행될 문을 작성break문
: fall Through를 방지하기 위해서 해당 사용함폴스루(fall Through)
: case문은 break가 없는한 계속해서 다음에 코드가 있으면 해당 코드를 실행함, 코드가 더이상 없을 때 끝나게 되는 현상 (switch의 조건식은 단지 해당 case로 보내고, 그 이후에 break가 없으면 다음 case, default 존재시 해당 코드를 실행함, default의 경우에는 break가 없어도 됨)- 여러개의 case문을 하나의 조건(즉, 같은 코드를 실행할 하나의 블럭)으로 사용가능
- 단지 break만 잘 위치시키면 됨
반복문
: 조건식의 평가 결과가 참인 경우 코드 블록을 실행후 다시 조건식을 다시 평가해서 참인 경우 다시 실행하고, 조건식이 거짓 일때 까지 반복- for문, while문, do...while 문
- 반복문 대체 기능: forEach, for...in, for...of
for문
: 조건식이 거짓일 때 까지 코드블록 반복실행- for (변수 선언문 or 할당문; 조건식; 증감식) { 조건식이 참인경우 실행될 문}
- 반복횟수가 명확 할 때 사용
while문
: 조건식이 거짓일 때 까지 코드블록 반복 실행- 반복횟수가 명확하지 않을 때 사용
- 조건식에 있는 평가 결과가 불리언이 아니면 불리언으로 강제 변환함
- if문으로 조건만들고 break 문으로 코드 블럭 탈출 가능
do...while문
: 코드 블럭을 먼저 실행하고 조건식을 평가하여 거짓일 때 까지 반복실행 함(무조건 한번 이상 블록 실행시 사용)
break 문
: 레이블 문, 반복문 또는 switch문에서만 코드 블록을 탈출함레이블문(label statement)
: 식별자가 붙은 문으로 프로그램의 실행 순서 제어하는데 사용됨(case, default문도 레이블 문임) , 그런데 비추함 별로 가독성 안좋음- 레이블문 탈출은 break문에 레이블 식별자를 지정함
- 중첩된 for문인 경우 내부 for에 break를 외부 for의 식별자를 사용하면 외부 for를 탈출함
continue문
: 반복문의 코드 블록 실행을 현 지점에서 중단하고 반복문의 증감식으로 실행 흐름을 이동시킴(반복문 안에서도 흐름을 제어하여 다음 반복으로 넘길 수 있음)- if로 구현하는게 더 가독성이 좋긴함, 실행 코드가 많다면, continue문을 사용하는 게 좋음