const num1 = 123;
const num2 = 123456789;
"hello world!"
"hello codestates!"
// "hello world!" 와 "hello codestates!"는 변경할 수 없는 고정된 값
let word = "hello world!"
word = "hello codestates!"
// 하지만 word라는 변수에 재할당을 하여 내용변경은 가능
const num1 = 123;
num1 = 123456789; // 에러 발생
// const 키워드로 선언하면 재할당 불가(let은 가능)
typeof null = 'object'
이다. 따라서 엄밀히 따지면 원시 타입이라고 볼 수 없으나, 원시 타입과 거의 같게 사용되며 작동 방식 또한 원시 타입이라고 볼 수 있다.자바스크립트에서 원시 자료형이 아닌 모든 것은 참조 자료형
배열([])과 객체({}), 함수(function(){})가 대표적
변수에는 특별한 데이터 보관함(heap)을 찾아갈 수 있는 주소(reference)가 담겨있고, 이 주소를 따라가보면 특별한 데이터 보관함을 찾을 수 있음
이 특별한 데이터 보관함은 자기 마음대로 사이즈를 늘렸다가 줄였다가 함 = 동적(dynamic)으로 변함
heap은 왜 동적으로 크기가 변하게 되었을까?
예제)
코드가 실행된 후, x.foo의 값은 무엇일까요?
let x = { foo: 3 };
let y = x;
y = 2;
x.foo // 3
코드가 실행된 후, score 의 값은 무엇일까요?
let score = 80;
function doStuff(value) {
value = 90;
}
doStuff(score);
score // 80
변수를 정의하는 또 다른 키워드, var (old way)
const 키워드
var myName = "Paul";
console.log(window.myName); //Paul
function foo(){
console.log('bar');
}
console.log(foo===window.foo); //true
🚫 선언 키워드(var, let, const)없이 변수를 할당하지 말 것!
function showAge(){
age = 90; // var로 선언한 전역변수처럼 취급됨
console.log(age); // 90
}
showAge();
console.log(age); // 90
console.log(window.age); // 90
이런 실수를 방지하기 위해 Strict Mode를 사용할 수 있다.
Strict Mode는 브라우저가 보다 엄격하게 작동하도록 만들어준다. 앞서 언급한 것처럼 "선언 없는 변수 할당"의 경우도 Strict Mode는 에러로 판단한다.
Strict Mode를 적용하려면, js 파일 상단에 'use strict' 라고 입력하면 된다. (따옴표 포함)
외부 함수의 실행이 끝나더라도, 외부 함수 내 변수를 사용할 수 있다.
유용한 클로저 예제 ⬇️
function htmlMaker(tag){
let startTag ='<'+tag+'>';
let endTag='</'+tag+'>';
return function(content){
return startTag + content + endTag;
}
}
let divMaker = htmlMaker('div');
divMaker('code'); // '<div>code</div>'
divMaker('states'); // '<div>states</div>'
// htmlMaker함수의 실행이 끝났지만 변수 tag에 문자열 'div'를 담아 사용 가능
let h1Maker = htmlMaker('h1');
h1Maker('Headline'); // '<h1>Headline</h1>'
// htmlMaker함수의 실행이 끝났지만 변수 tag에 문자열 'h1'을 담아 사용 가능
function makeCounter(){
let privateCounter = 0;
return {
increment: function(){
privateCounter++;
},
decrement: function(){
privateCounter--;
},
getValue: function(){
return privateCounter;
}
}
}
let counter1 = makeCounter();
counter1.increment();
counter2.increment();
counter2.getValue(); // 2
let counter2 = makeCounter();
counter2.increment();
counter2.decrement();
counter2.increment();
counter2.getValue(); // 1
privateCounter라는 변수는 어떤 경우에도 직접 수정이 불가능하지만, 리턴하는 객체가 제공하는 메소드를 통해 privateCounter의 값을 간접적으로 조작할 수 있다.
이것이 바로 정보의 접근 제한(캡슐화)이다.
이렇게 하지 않고 privateCounter를 전역 변수로 선언할 경우, 다른 함수 혹은 로직 등에 의해 의도치 않게 값이 변경될 수 있다. 이를 side effect라고 한다. 클로저를 사용해 불필요한 전역 변수 사용을 줄여, 값을 보다 안전하게 다룰 수 있다.
위의 예제 코드에서 makeCounter 함수를 이용해 여러 개의 함수를 만든 것을 확인했다. counter1과 counter2의 privateCounter는 서로에게 영향을 미치지 않고, 각각의 값을 보존할 수 있다. 이와 같이 함수 재사용성을 극대화하여 함수 하나를 독립적인 부품 형태로 분리하는 것을 모듈화라고 하며, 클로저는 모듈화에 유리하다.