728x90
반응형
1. Symbol, BigInt 데이터
// Symbol
// 변경이 불가한 데이터로, 유일한 식별자를 만들어 데이터를 보호하는 용도로 사용 가능
// Symbol('설명')
// 설명은 단순 디버깅을 위한 용도일 뿐, 심볼 값과는 관계가 없음
const sKey = Symbol('hello!')
const user = {
key: '일반 정보',
[sKey]: '민감한 정보'
}
console.log(user.key)
console.log(user['key'])
console.log(user[sKey])
console.log(user[Symbol('hello!')]) // undefined
console.log(typeof sKey) // Symbol(hello!)
// BigInt
// BigInt는 길이 제한이 없는 정수
// 숫자 데이터가 안정적으로 표시할 수 있는
// 최대치(2^53 - 1)보다 큰 정수를 표현 가능
// 정수 뒤에 n을 붙이거나 BigInt()를 호출해 생성
console.log(123456789876543234567898765434567)
console.log(1234567898765432345676543234567n)
console.log(BigInt('123456787654323456789765432134567876543'))
const a = 11n
const b = 22
// 숫자 => BigInt
console.log(a+BigInt(b))
console.log(typeof(a+BigInt(b)))
// BigInt => 숫자
console.log(Number(a)+b)
console.log(typeof(Number(a)+b))
2. 불변성과 가변성
// 가변성 / 불변성
// 불변성 : Immutability는 생성된 데이터가 메모리에서 변경되지 않고,
// 가변성 : Mutability는 생성된 데이터가 메모리에서 변경될 수 있음을 의미
// js는 원시형은 불변성을, 참조형은 가변성을 가지고 있음
// 같은 참조형의 메모리 주소를 바라보고 있는 여러 변수를 관리할 때는
// 한쪽에서 바꾼 내용이 다른 쪽에서도 영향을 미칠 수 있기 때문에 주의(복사됨)
let a = 1 // 숫자는 원시형, 객체/함수/배열은 참조형
let b = a
b = 2
console.log(b)
console.log(a)
// 배열데이터 예시
let c = [1,2,3]
let d = c
d[0] = 4
console.log(c)
console.log(d)
3. 얕은 복사와 깊은 복사
// 얕은 복사와 깊은 복사
// 참조형은 가변성으로 인해, 데이터를 복사할 때 주의 필요
// 얕은 복사(shallow copy) - 참조형의 1차원 데이터만 복사 (껍데기만 복사)
// 깊은 복사(deep copy) - 참조형의 모든 자원 데이터를 복사 (껍데기만 복사하는 게 아님)
// 원시형 데이터는 할당 연산자를 사용해도 b 변수가 a 변수에 영향 안끼침
let a = 1
let b = a
b = 2
console.log(b)
console.log(a)
b = 3
console.log(b)
console.log(a)
// 얕은 복사 - object.assign() 사용
const a = {x:1}
// 객체 데이터의 속성을 복사해서 새로운 데이터 만드는 용도
// Object.assign(대상객체, 출처객체)
const b = Object.assign({}, a)
b.x = 2
console.log(a)
console.log(b)
// 얕은 복사 - 전개연산자 사용
const c = {x:1}
const d = {...a}
d.x = 2
console.log(c)
console.log(d)
// 얕은 복사
const e = {x : { y : 1 } }
const f = {...e} // 얕은 복사
f.x.y = 2
console.log(e)
console.log(f)
// 깊은 복사 - cloneDeep
import cloneDeep from 'lodash/cloneDeep'
const a = {x : {y:1}}
const b = cloneDeep(a) // 얕은 복사
b.x.y = 2
console.log(a)
console.log(b)
4. 가비지 컬렉션
// 가비지 컬렉션(GC, 쓰레기 수집)
// js의 메모리 관리 방법으로 js 엔진이 자동으로,
// 데이터가 할당된 메모리에서 더 이상 사용되지 않는 데이터를 해제하는 것
// 가비지 컬렉션은 개발자가 직접 강제 실행하거나 관리할 수 없음
let a = {x:1}
let b = a
b.x = 2
console.log(a)
console.log(b)
// 예제2
const user = {
name : 'test',
age : 20,
emails : ['test@test']
}
delete user.emails // 바로 제거되는 건 아니고, 가비지 컬렉션 순회할 때, 사용하지 않을 경우 메모리에서 해제됨
console.log(user)
5. 클로저
// 클로저(Closure)
// 함수가 선언될 때의 유효범위(렉시컬 범위)를 기억하고 있다가,
// 함수가 외부에서 호출될 때 그 유효범위의 특정 변수를 참조할 수 있는 개념
// 상황에 따라 재사용되는 부분에서 초기화돼서 계속 값을 누적 가능
// function createCount() {
// let a = 0
// return function () {
// return a+=1
// }
// }
// const count = createCount()
// console.log(count())
// console.log(count())
// console.log(count())
// const count2 = createCount()
// console.log(count2())
// console.log(count2())
// 예제 2
const h1El = document.querySelector('h1')
const h2El = document.querySelector('h2')
// 별도의 상태 관리가 필요
// let h1IsRed = false
// let h2IsRed = false
// h1El.addEventListener('click', event => {
// h1IsRed = !h1IsRed
// h1El.style.color = h1IsRed ? 'red' : 'black'
// })
// h2El.addEventListener('click', event => {
// h2IsRed = !h2IsRed
// h2El.style.color = h2IsRed ? 'red' : 'black'
// })
// 하나의 함수로 정리
const createToggleHandler = () => {
let isRed = false
return event => {
isRed = !isRed
event.target.style.color = isRed ? 'red' : 'black'
}
}
// 함수 호출 시, return 키워드로 반환되는 데이터가 남음
// h1 클릭할 때 동작하는 콜백함수가 createToggleHandler 함수가 반환하는 그 내부의 클로저
// 클릭할 때마다 isRed 데이터가 누적되어 지속적으로 관리 가능
h1El.addEventListener('click', createToggleHandler())
h2El.addEventListener('click', createToggleHandler())
6. 메모리 누수
// 메모리 누수(memory leak)
// 더 이상 필요하지 않은 데이터가 해제되지 못하고 메모리를 계속 차지되는 현상
// 불필요한 전역 변수 사용 - 가비지 컬렉션으로 해제 안됨
window.hello = 'hello'
window.test = { name: 'test', age:12}
// 분리된 노드 참조
// const btn = document.querySelector('button')
// const parent = document.querySelector('.parent')
// btn.addEventListener('click', () => {
// console.log(parent)
// parent.remove() // 요소만 제거하고, 메모리 주소는 제거 안됨
// })
// 분리된 노드 참조 수정
const btn = document.querySelector('button')
btn.addEventListener('click', () => {
const parent = document.querySelector('.parent') // 클릭할 때만 parent 찾기
console.log(parent)
parent && parent.remove() // 가장 먼저 만난 거짓 데이터 반환, parent 못찾으면 null 데이터 반환
})
// 해제하지 않은 타이머
// clear로 꼭 해제해야함
let a = 0
const intervalId = setInterval(() => {
a+=1
}, 100);
setTimeout(() => {
console.log(a)
clearInterval(intervalId)
}, 1000);
// 잘못된 클로저 사용
const getFn = () => {
let a =0
return name => {
// a는 클로저로 메모리 낭비 중, 결과로 필요없는 내용
a+=1
console.log(a)
return `hello ${name}~`
}
}
const fn = getFn()
console.log(fn('he'))
console.log(fn('aae'))
console.log(fn('te'))
7. 콜 스택, 테스트 큐=콜백 큐, 이벤트 루프
- js에서 직접적으로 동작할 수 있는 코드( ex) console.log )는 call stack(LIFO 방식)에 계속 쌓여서 바로 실행이 가능
- setTimeout 같은 함수는 js 내부에서 지원하는 기능이 아니기에 브라우저에서 제공하는 web api 도움을 받아서 실행
- 그렇게 실행될 때 들어가는 콜백 함수는 web api를 통해서 바로 call stack으로 가는 것이 아니고,
task queue(FIFO 방식)에 쌓이는 구조
- 쌓인 콜백 함수는 js call stack의 내용이 완전히 비워줘야 event loop를 통해 call stack으로 들어갈 수 있음
728x90
반응형
'JS, TS' 카테고리의 다른 글
[JS] 컴포넌트 (0) | 2024.01.16 |
---|---|
[JS] 정규표현식 (0) | 2024.01.16 |
[JS] 기타 Web APIs (1) | 2024.01.15 |
[JS] 이벤트 2 (0) | 2024.01.15 |
[JS] 이벤트 1 (0) | 2024.01.15 |