타입
타입의 종류
- 기본형 (Primitive type)
- null
- undefined
- boolean
- number
- string
- 복합형 (Non-Primitive type)
- object
- array
타입을 체크하는 방법
console.log(typeof a);
Undefined? Undefined(Undeclared)?
- 두 변수들의 값을 출력하려고 한다. 이 때 선언이 되었지만 값이 없는 변수 a 와 선언조차 되지 않은 변수 b가 있다.
var a; console.log(a); // undefined
console.log(b); // ReferenceError: b is not defined
- b를 출력할 때 에러가 난다. 이해가 가는 내용이다.
- 이어서 두 변수들의 타입을 출력하려고 한다. 이 때 선언이 되었지만 값이 없는 변수 a 와 선언조차 되지 않은 변수 b가 있다.
-
var a; console.log(typeof a); // undefined console.log(typeof b); // undefined (undeclared)
- 두개를 모두 출력하면
undefined
라는 값이 출력된다.a
야 정의되지 않은 것이 맞긴 하지만, 선언조차 되지 않은b
또한 에러가 뜨지 않고 똑같이undefined
를 출력한다. - 이 점을 활용하여 Reference Error의 안전 가드로 사용할 수 있다. 임의의 변수를 사용하려고 할 때, 이 변수가 선언이 아예 되지 않았는지, 또는 값이 없는지를 체크할 수 있다는 점에서 착안하였다.
if (typeof a === "undefined") console.log("변수가 올바르게 선언되지 않았습니다"); if (typeof b === "undefined") console.log("변수가 올바르게 선언되지 않았습니다");
-
JavaScript의 변수의 타입
- (const를 제외하고) 변수를 선언한 이후 재 할당이 가능하다. 즉 변수가 가진 타입이 계속 바뀔 수 있다는 것이다.
- 따라서 변수에 typeof 연산자를 대어보는 건 "이 변수의 타입은 무엇이니?" 라는 질문과 같지만, 실은 타입이란 개념은 변수에 없으므로 정확히는 "이 변수에 들어있는 값의 타입은 무엇이니?" 라고 묻는 것이다.
var, let, const의 차이
- var과 let, const의 차이는 무엇일까?
- scope가 다르다.
var
: function-scopedlet & const
: block-scoped
- 재 선언, 재 할당 여부가 다르다.
- scope가 다르다.
Function scope, Block scope
- Function scope
- function scope를 갖는
var v
는 이처럼 함수 안에서만 존재한다.
- function scope를 갖는
function f() { var v = 5; console.log(v); // 5 } console.log(v); // ReferenceError: v is not defined
- Block scope
- block scope를 갖는
let a
는 이처럼 block 안에서만 존재한다.
- block scope를 갖는
for (let a = 0; a < 5; a++) { console.log(a); // 0 1 2 3 4 } console.log(a); // ReferenceError: a is not defined
var, let, const는 어디에 저장이 될까?
전부 heap에 저장되나요 아니면 일반적인 변수, 상수처럼 heap, stack에 저장되나요?
- 이는 데이터의 type에 따라 결정이 된다.
- Primitive type (null, undefined, boolean, number, string) 의 경우 stack에, Non-Primitive type (array, object) 의 경우 heap에 저장된다.
Hoisting
Hoisting의 예시와 개념
- 그렇다면, 이건 결과가 어떻게 나올까? 마지막줄의
console.log()
는 출력이 될까?- 답은 그렇다. 출력 결과는 아래와 같다.
j 0 j 1 j 2 j 3 j 4 j 5 j 6 j 7 j 8 j 9 after loop j is 10
for(var j=0; j<10; j++) { console.log('j', j); } console.log('after loop j is ', j);
after loop j is 10
이 출력이 될 수 있는 이유는, 컴파일 과정 중에var j
를 맨 윗부분에서 선언해주기 때문이다. 즉 위의 코드는 아래와 같은 내용인 것이다var
가 function scope 를 갖는다면서 왜 for문 안이 아니라 전역에 선언이 된 것일까? 왜냐하면 for문은 함수가 아니기 때문이다.
var j; for (j = 0; j < 10; j++) { console.log("j", j); } console.log("after loop j is ", j);
- 이처럼 컴파일 과정 중에 선언문을 맨 위로 끌어올려주어, 해당 scope 내에서 선언과 사용의 순서에 상관 없이 사용할 수 있도록 하는 것을
Hoisting
이라 한다. 함수가 변수보다 우선시된다. - 1번과 2번 코드는 3번과 같다. 4번의 경우
ReferenceError
가 뜨지 않고undefined
가 뜨는 이유는, 생각해보건대var foo;
는 맨 위로 끌어올려졌지만 값 할당이console.log()
이후에 일어났기 때문에 var foo가 선언만 되고 값이 할당이 되지 않아서 undefined가 나온 것 같다. // 1. foo = "bar"; var foo; console.log(foo); // bar // 2. foo = "bar"; console.log(foo); // bar var foo; // 3. var foo; foo = "bar"; console.log(foo); // bar // 4. console.log(foo); // undefined foo = "bar"; var foo;
Hoisting이 일어나는 경우와 그렇지 않은 경우
- var 변수/함수의 선언만 위로 끌어올려진다.
- const, let 같이 선언과 동시에 할당이 되는 경우 에는 끌어올려지지 않는다.
Hoisting 여부 | |
---|---|
var | O |
let | X |
const | X |
- 사실 Hoisting이 일어나지 않는 것은 아니다. 내부적으로는 모두 Hoisting이 일어나지만 TDZ로 인해 (실행 결과만 봤을 때에는 -let, const, 함수 선언식은- ReferenceError가 뜬다) hoisting이 일어나지 않는 것 처럼 보인다.
// 출력을 선언보다 먼저했다 // let & const console.log(a); // ReferenceError: a is not defined console.log(b); // ReferenceError: b is not defined let a = "a"; const b = "b"; // 함수 선언식 console.log(ff("15")); // ReferenceError: ff is not defined const ff = function(v) { // 함수 표현식 return v; };
var보다 let, const 사용을 지향하는 이유는 Hoisting과 관련이 있다고 생각한다
- let과 const가 등장한 이래로 var보다는 let, const 사용을 지향해오고 있다. 그 이유는, 생각해보건대 hoisting 때문인 것 같다. var는 (for문의 예시 처럼) 종종 예측하기 어려운 상황을 만들 수 있다.
함수
함수 선언문
- 구성 요소
- 함수 이름
- 매개변수
- 함수 몸체
- (optional: 반환 값)
function square(number) {
return number*number;
}
함수 표현식
- 함수의 선언과 동시에 변수에 할당한다.
var square = function(number) { return number*number; };
- 함수가 선언될 때, 함수에 이름이 있냐 없냐에 따라 기명/익명 함수로 나뉜다.
- 기명 함수
var foo = function multiply(a, b) { return a*b; };
- 익명 함수
var bar = function(a, b) { return a * b; };
- 함수 표현식이 뭔지는 알겠는데, 굳이 왜 하는걸까? 변수 안에 함수를 넣어야 하는 이유는 무엇일까?
- 유성이가 또 좋은 질문을 해주었다. 그동안 그저 변수에 함수를 넣기만 했지, 왜 그렇게 썼는지 고민을 해 본 적이 없었다.
- 이유는 함수를 변수처럼 사용하기 위해서 이다. 이를테면,
- 다른 함수의 인자로써 사용하거나
- 리턴 값으로 사용하거나
- 변수나 객체에 할당하거나
- 동적으로 객체의 프로퍼티를 생성 또는 할당하거나
- 를 하기 위해서 이다.
참고 자료
- JavaScript의 변수의 타입 / 책 - You don’t know JS 30page
- var, let, const / 책 - You don’t know JS 234page
- Undefined? Undefined? / 책 - You don’t know JS 34page
- var, let, const는 어디에 저장이 될까? [StackOverflow] Primitive value vs Reference value
- JavaScript는 Compile 언어일까 Interpreter 언어일까?
- Hoisting
- 조건문 https://www.opentutorials.org/module/570/4962
- 함수 https://poiemaweb.com/js-function
'자바스크립트 JavaScript' 카테고리의 다른 글
Closure (0) | 2023.01.18 |
---|---|
Scope (0) | 2023.01.18 |
실행 컨텍스트 (Execution Context) (2) | 2023.01.17 |
JITC, Adaptive-JITC (0) | 2023.01.17 |
JavaScript 의 역사 (0) | 2023.01.16 |