
var name = '박경빈';
console.log(name); //박경빈
var name = '홍길동';
console.log(name); //홍길동
1. var
{
var a = 3;
console.log(a); //3
}
console.log(a); //3
2. let
{
let a = 3;
console.log(a); //3
}
console.log(a); //Uncaught ReferenceError: a is not defined
할당 => 사용 => 해제 (3가지 과정)
JS 엔진은 Garbage Collector를 통해 메모리를 정리한다.
Gabage Collector
Gabage Collection이라는 자동 메모리 관리 알고리즘을 통해 만들어진 객체
사용하지 않는 메모리를 해제하는 역할을 한다.
Mark and Sweep Algorithm을 사용
쓰지않는 주소를 필요없는 주소로 인지하고 삭제하는 알고리즘
예시
let a = 126
let b = a
a = a + 1 // a = 127
b = a + 1 // b = 127
// 위의 경우 126을 참조하는 변수가 없기 때문에 GC가 126이 할당된 메모리를 정리한다.
JS에서 원시타입은 변경이 불가능하다. → 원시 타입의 값이 변경될 때는 새로운 메모리가 할당된다.
let variable = 126 // 주소: 111
let variable2 = variable //variable2는 variable의 주소를 가리키고 있는 상태(주소: 111)
variable = variable + 1 // 주소:111의 값이 변경되지 않고 variable은 주소: 112를 가리킴(값은 127)
JS의Virtual Machine(가상 머신)의 메모리 모델
Heap: 참조타입이 들어감, 동적으로 크기 변경이 가능함
Call Stack: 원시타입이 들어감
예시
let a = 10; // call stack
let b = 20; // call stack
const arr = []; // Heap (call stack에서 생성된 배열 변수 arr이 Heap의 배열 영역을 메모리 주소를 참조)
arr.push(5); // Heap 메모리를 변경하는 것이기 때문에 상수여도 push가 동작함
arr.push(3);
arr.push(1);
const arr1 = new Array();
const arr2 = [];
const arr3 = [1, 2, 3, 4, 5];
const arr4 = new Array(5);
const arr5 = new Array(5).fill(5); // [5, 5, 5, 5, 5] 5로 초기화 해준다.
const arr6 = Array.from(Array(5), function(v, k) {
return k + 1;
}) // [1, 2, 3, 4, 5]
const arr = [1, 2, 3];
// push 배열 끝에 새로운 요소 추가
arr.push(4); // [1, 2, 3, 4]
// pop 배열 끝의 요소 삭제
arr.pop(); // [1, 2, 3]
// shift 배열 맨 앞의 요소 삭제
arr.shift(); // [2, 3]
// unshift 배열 맨 앞에 요소 추가
arr.unshift(1); // [1, 2, 3]
const joinArr = [1, 2, 3, 4, 5, 6];
// join
console.log(joinArr.join(", ")); // 1, 2, 3, 4, 5, 6
// reverse
console.log(joinArr.reverse()); // [ 6, 5, 4, 3, 2, 1 ]
console.log(joinArr); // [ 6, 5, 4, 3, 2, 1 ] => 원본 배열에도 영향을 준다.
// concat
const a = [1, 2, 3];
const b = [4, 5, 6];
console.log(a.concat(b)); // [ 1, 2, 3, 4, 5, 6 ]
// slice
// 중간의 요소를 잘라서 가져오고 싶다면 slice
const arr = [1, 2, 3, 4, 5, 6];
// 첫 번째 인자: 시작점, 두 번째 인자: 끝나는 점
console.log(arr.slice(2, 4)); // [ 3, 4 ]
console.log(arr); // [ 1, 2, 3, 4, 5, 6 ] => 원본 배열이 변하지 않음
// splice: 중간 요소를 삭제
arr.splice(2, 2); // 첫 번째 인자: 시작점, 두 번째 인자: 삭제할 개수
console.log(arr); // [ 1, 2, 5, 6 ]
for (let i = 0; i < 5; i += 1) {
console.log(arr[i]);
}
// 추천하는 방식
for (const item of arr) {
console.log(item);
}
const arr = [1, 2, 3, 4, 5];
console.log(typeof arr); //object 출력 => 배열은 객체 타입이다.
arr['key'] = 'value';
console.log(arr); // [ 1, 2, 3, 4, 5, key: 'value' ]
console.log(arr.length); // 5 => key가 추가되었지만 배열의 길이는 변하지 않는다.
여러 값을 키-값 형태로 결합시킨 복합 타입
const obj1 = new Object();
const obj2 = {};
const obj3 = {name: 'Gun', company: 'dev'};
const obj = {};
obj["email"] = "foxrain.gg@gmail.com"; // 요소 추가 방법1
obj.phone = '01012345678'; // 요소 추가 방법2
console.log(obj); // { email: 'foxrain.gg@gmail.com', phone: '01012345678' }
delete obj.phone;
console.log(obj); // { email: 'foxrain.gg@gmail.com' }
// 객체 요소 유무 확인 방법
console.log('email' in obj); // true
console.log('phone' in obj); // false
const obj = {
email: "foxrain.gg@gmail.com",
phone: "01012345678",
};
// 키의 집합
console.log(Object.keys(obj)); // [ 'email', 'phone' ]
// 값의 집합
console.log(Object.values(obj)); // [ 'foxrain.gg@gmail.com', '01012345678' ]
const obj = {
email: "foxrain.gg@gmail.com",
phone: "01012345678",
};
// for in은 객체의 키 값을 순회함
for (const key in obj) {
console.log(key, obj[key]);
// 1번째 실행: email foxrain.gg@gmail.com
// 2번째 실행: phone 01012345678
}
유효 범위라고도 부르며 변수가 어느 범위까지 참조되는지를 뜻한다.
const a = 5; // Global Scope
{
const b = 3; // Local Scope
console.log(a, b); // 5 3
}
console.log(a, b); // Error
함수가 선언된 환경의 스코프를 기억하여 함수가 스코프 밖에서 실행될 때에도 기억한 스코프에 접근할 수 있게 만드는 문법
function makeGreeting(name) {
const greeting = "Hello, ";
return function() {
console.log(greeting + name);
};
}
const world = makeGreeting("World!");
const gunwoo = makeGreeting("GunWoo");
world();
gunwoo();
클로저를 사용하여 내부 변수와 함수를 숨길 수 있다.
function Counter() {
let privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
getValue: function() {
return privateCounter;
},
}
}
const counter = Counter();
const counter2 = Counter();
console.log(counter.getValue()); // 0
counter.increment();
counter.increment();
console.log(counter.getValue()); // 2
counter.decrement();
console.log(counter.getValue()); // 1
console.log(counter2.getValue()); // 0 => 별개의 클로저
function counting() {
let i = 0;
for (i = 0; i < 5; i += 1) {
setTimeout(function () {
console.log(i);
}, i * 100);
}
}
counting(); // 5가 다섯번 출력됨
// setTimeout의 대기시간이 끝나 callback fuction이 실행되는 시점에는 루프가 종료되어
// i가 5인 상태이기 때문이다.
IIFE(Immediately Invoked Function Expression, 즉시 실행 함수)를 사용한다.
function counting() {
let i = 0;
for (i = 0; i < 5; i += 1) {
(function (number) {
setTimeout(function () {
console.log(number);
}, number * 100);
})(i);
}
}
counting(); //0 1 2 3 4 출력
let을 사용한다. ⇒ let은 블록 수준 스코프이기 때문에 매 루프마다 클로저가 생성된다.
function counting() {
for (let i = 0; i < 5; i += 1) {
setTimeout(function () {
console.log(i);
}, i * 100);
}
}
counting(); //0 1 2 3 4 출력
작년에 클로저에 대해서 공부를 했었는데 이번에 다시 공부해보니.. 하나도 기억이 안나는거 같다.. 더 열심히 복습하고 공부해야할거같다.
밑에는 작년에 정리했던 클로저 글이다.