그동안 JS의 기본적인 데이터와 문법에 대해서 공부해봤다.
이제 그 문법이 어떻게 구성되고 데이터를 처리하는 로직이 어떻게 진행되는지 더 자세하게 확인하고 공부하자!
primitive data type
)과 참조 자료형(reference data type
)의 구분이 왜 필요한지에 대해서 영상을 보고 이해value
) 자체가 담기고, 참조 자료형이 할당될 때는 보관함의 주소(reference
)가 담긴다는 개념을 코드로 설명
- 고정된 저장 공간을 차지하는 데이터
- 타입 부분에서 배웠듯
Stack
이라는 메모리 주소의 사물함에 저장하고 꺼내 쓰는 데이터- 하나의 데이터 메모리 주소(사물함)에 하나의 값만 있는 형태, 옛날에 용량이 제한될 때 썼던 방식이라 그래서 '원시'라는 표현을 씀
number
,string
,boolean
,undefined
, (null
) 등
원시 자료형에서 대량의 데이터가 들어왔을 때, 고정된 데이터 공간을 사용하는 것이 비효율적이라고 느꼈음. 예를 들어 하나의 값만 넣는 것에 한계를 느꼈고, 하나의 사물함의 용량에도 한계를 느껴 "데이터의 크기가 동적으로 변하는" 특별한 데이터 보관함이 필요해졌음
- 변수에 값이 아닌 주소를 저장, 그 주소로 가면 특별한 '사물함'(데이터가 담긴 저장소)이 생김
- 이 '사물함'의 명칭은 'Heap'이고, 용량을 마음대로 조절할 수 있음, 즉! 동적임!
- 실생활에선 Reperence, 즉 '자료를 찾는다.'의 의미지만 공학에선 정확히 변수가 가리키고(refer) 있는 데이터를 참조한다는 의미임
let x = 2;
let y = x; // 값이 같지만 다른 메모리 주소가 할당
y = 3; // 그러므로 y가 변해도 영향 x
let x = [10, 20, 30, 40];
let y = x; // 다른 메모리 주소지만 그 안에 있던 Heap이 같음
y[0] = 5; // 그 Heap이 변했으니 x도 변함(얕은 복사)
let player = { score: 3 }; // 3. score이 2로 변함
function doStuff(obj) { // 2. 함수 호출
obj.score = 2; // 2-1. 같은 Heap 주소끼리 공유돼 변함, 사물함이면 원본 안변함
}
doStuff(player); // 1. 함수 실행, player를 인수로 넣어 호출
console.log([1,2,3] === [1,2,3]);
console.log({ foo: 'bar' } === { foo: 'bar' });
// false false, 다 다른 heap 저장 공간의 주소를 확보
let myArray = [2, 3, 4, 5];
let ourArray = myArray; // 사물함은 다르지만 Heap은 같음
ourArray[2] = 25; // myArray의 heap은 [2, 3, 25, 5]
ourArray = undefined; // ourArray는 undefined, my는 안변함
Scope는 range랑 비슷한 의미, 즉 범위를 나타냄, 공학에선 '변수의 유효 범위'를 뜻함! 이제 알아보자
let
, const
, var
)와 스코프와의 관계를 설명let name = "윤뿔소"
function showname1() {
let name = '코뿔소'; // 선언 o
console.log(name);
}
function showname1() {
name = '코뿔소'; // 선언 x
console.log(name);
}
console.log(name); // '윤뿔소'
showname(); // '코뿔소'
console.log(name); // 1: '윤뿔소', 2: '코뿔소'
- 중괄호 안에서 선언된 변수의 범위를 뜻함
- ⭐️화살표 함수가 있는데 화살표 함수는 블록 스코프임!!
함수 안에서 선언된 변수의 범위를 뜻함
var
로 선언된 변수는 블록 스코프를 무시하고 함수 스코프만 따름, 물론 예외도 있음(화살표 함수는 무시안함), 그래서 직관적이지 못하고 코드가 혼란스러울 수도 있음, 초보들한텐 직관적인 let
, const
권장var
는 재선언이 가능함, let
, const
는 재선언 불가능, 훨씬 안정적const
는 재할당 불가, 그러므로 의도하지 않은 값의 변경을 막을 수 있음!Side Effect
발생var
는 쓰지않도록 주의하자함수가 여러개라면? 여러개가 있는데 그에 따른 변수들을 가져올 수 싶다면?
adder(5)
라는 값을 add5
라는 변수에 담았음divMaker
함수는 div
라는 문자열을 tag
라는 변수에 담아두어 div
태그를 만듬 여기서 클로저를 통해 content
를 변수로 불러냄
const tagMaker = tag => content => `<${tag}>${content}<${tag}>`
const divMaker = tagMaker('div');
divMaker("Hello") // '<div>Hello<div>'
divMaker("Rhino") // '<div>Rhino<div>'
makeCounter
가 value
를 선언, 0으로 할당시킨뒤 함수들을 객체 데이터로 넣고 불러와지면 카운트하는 형식의 코드임const makeCounter = () => {
let value = 0;
return {
increase: () => {
value = value + 1
},
decrease: () => {
value = value - 1
},
getValue: () => value
}
}
const counter1 = makeCounter();
counter1.increase();
counter1.increase();
counter1.decrease();
counter1.decrease();
counter1.increase();
counter1.getValue(); // 맞춰봐라!
value
의 값을 로컬 스코프에서 선언해 정보의 은닉을 할 수 있고 깔끔하게 쓸 수 있기 때문에 모듈화를 할 수 있는 것임!outer()
의 변수 x
는 원래 죽는거지만 inner
의 내부 함수로 밖에서도 꺼내쓸 수 있음즉 변수를 살려내는 방법임f2
부터 변수 b
는 함수 안에 있기에 초기화됨, 즉! f1 === f2
는 독립된 렉시컬 스코프가 다르기에 false
가 나옴!var a = 0;
function foo() {
var b = 0;
return function() {
console.log(++a, ++b);
};
}
var f1 = foo();
var f2 = foo();
f1(); // --> 1, 1
f1(); // --> 2, 2
f2(); // --> 3, 1 - f2를 새로 실행, 렉시컬 환경이 달라져 변수가 쌓이는 것이 달라짐
f2(); // --> 4, 2
+ 즉시실행함수, 삼항연산자(isShow ? 'block' : 'none'), 스타일객체(box.style.display)