본문 바로가기
JS

JS 3일차(1)

by teg0 2025. 9. 22.

Hoisting

JS 엔진이 코드를 실행하기 전에 모든 변수선언과 함수선언을 메모리에 미리 등록해 두는 동작.

그래서 선언이 코드 아래에 있어도 마치 코드의 최상단으로 끌어올려진 것처럼 동작.

 

TDZ(Temporal Dead Zone)

let/const 변수가 선언되기 전까지 해당 변수를 기록해 두는 공간으로 해당영역에 표시된 변수는 아직 선언시점이 되지 않은 변수로 구분한다.

 

호이스팅 영역 : name1, name2, name3

TDZ 영역 : name2, name3

const, let은 var와 다르게 tdz를 이용해서 마치 호이스팅이 일어나지 않은 것처럼 동작하게 해 준다.

console.log("선언 전 : ", name1);
var name1 = "jiwon";
console.log("선언 후 : ", name1);

// console.log(name2);
//일반변수
let name2 = "sumin";

//일반상수
const name3 = 'jisu';

 

함수의 선언문은 전체 함수가 메모리에 먼저 등록(호이스팅)되기 때문에 코드 어디서든 호출이 가능함.

hello();

function hello(){
    console.log("안녕하세요.")
}

 

Scope

스코프는 변수와 함수가 접근할 수 있는 유효범위이며, 이 변수/함수가 어디까지 보이고, 어디까지 쓸 수 있는지를 결정

 

전역스코프 : 코드 어디서든 접근 가능한 영역(전역에서 선언된 변수/함수)
함수스코프 : 함수 내부에서만 접근 가능한 영역(var 키워드로 선언한 값)
블록스코프 : {} 블록 내부에서만 접근이 가능한 영역(let, const 키워드로 선언한 값)
렉시컬스코프 : 선언된 위치 기준으로 스코프를 결정(js는 렉시컬 스코프를 기반으로 함) 전역스코프

 

var num1 = 20;

function test1(){
    console.log(num1);
}

function test2(){
    var num1 = 40;
    console.log(num1);
}

test1()은 전역 변수 참조 20을, test2()는 함수 내부 변수 참조로 40이 출력하는데,

함수 내부에 값이 있으면 그 값을 사용, 없다면 전역에서 값을 찾아 사용한다.

 

var num1 = 20;
var num2 = 10;

function test3(){
    var num1 = 40;
    let num2 = 20;
    test4();
    console.log("num1 in test3 : " + num1);
}

function test4(){
    var num2 = 11;
    console.log("num1 in test4 : " + num1);
    console.log("num2 in test4 : " + num2);
}

test3();
console.log("전역 num1 : " + num1);

test4()는 test3안에서 호출되었지만, test3()의 num1/num2를 가져오지 않고 자신이 선언된 위치에서의 전역 스코프 변수를 가져온다. -> 렉시컬 스코프

 

렉시컬 스코프의 반대 의미는 동적스코프이다.

동적스코프는 함수가 실행된 위치기준으로 스코프가 결정된다.

 

var i = 1000;
for(var i=0; i<10; i++){
    console.log(i);
}
console.log("i = " + i);

let j=1000;
for(let j=0;j<10;j++){
    console.log(j);
}

console.log("j = " + j);

var는 함수 스코프이기 때문에 for문내에 새로운 i가 생기지않고 전역에 i를 저장하며, for문이 종료되어도 전역 i는 그대로 유지된다.
let, const는 블록 스코프이기때문에 for문내에 새로운 스코프를 만들고 j를 해당 스코프에 저장해 사용한 뒤 for문이 종료되면 제거된다.
별개로 전역에 있는 j는 그대로 전역변수로 사용된다.

따라서 i는 10이 출력되고 j는 1000이 출력된다.

 

Closure

클로저는 함수와, 그 함수가 선언된 시점의 렉시컬 환경의 조합.

즉, 내부함수의 선언시점에 외부함수의 변수를 함께 저장해서 사용하는 것을 클로저라고 함.

콜백/이벤트 핸들러/모듈패턴에서 핵심적인 역할을 함.

 

function getCounter(){
    //count는 getCounter영역에 선언된 변수
    let count = 0;

    function increase(){
        count++;
        return count;
    }

    return increase; //내부함수를 반환 -> 외부에서도 count에 접근 가능
}

const run = getCounter();
console.log(run());

count는 getCounter 변수이지만, run이 살아있을 경우 count는 increase에서 상태유지된다.

따라서 한번 더 run()을 콘솔창에 실행시키면, 한 번 더 증가된 값인 2가 출력된다.

 

let run1 = getCounter();
let run2 = getCounter();
let run3 = getCounter();

console.log(run1());
console.log(run1());
console.log(run1());

console.log(run2());
console.log(run2());
console.log(run2());

console.log(run3());
console.log(run3());
console.log(run3());

 

또한 각 변수에 getCouner를 실행할 경우 새로운 렉시컬 환경이 만들어지며 서로 독립적은 상태값을 가진다.

 

function createStore(initial = 0){
    let value = initial;

    return {
        get: function(){return value;},
        set: function(v){value = v;},
        increase: function(){value++; return value;}
    };
}

const store = createStore(10);
console.log(store.get());
store.increase();
store.set(100);
console.log(store.get());

 

initail의 초기값을 0으로 설정(안 할 경우 undefined가 출력됨.)

return을 통해 자바의 getter, setter처럼 가능하다. 

즉 외부에서 value를 직접 접근이 불가하며 메서드로만 조작이 가능하다.

 

예)

버튼을 여러 번 눌러도 처음 한 번만 출력이 되도록 할 수 있다.

function attachOnce(el, msg){
    let clicked = false; //지역상태(클로저 생성)

    el.addEventListener("click", function(){ //이벤트리스너 등록
        if(clicked) return; //클릭한적이 있냐?
        clicked = true; //클로저에있는 clicked -> true
        console.log(msg); //클릭시 하고자하는 동작을 수행
    })
}

 

ArrayFunction

배열에 값을 추가하려면 push("값");

members.push("신지원");

 

배열에서 인덱스 기준 n개만큼 잘라내려면 splice(인덱스, n);

members.splice(1, 3);

 

배열에서 인덱스 기준 마지막 인덱스 -1개를 추출하려면 (원본에 지정 없음)  slice(인덱스, 마지막 인덱스 -1);

members.slice(0, 3);

 

배열이나 객체의 요소를 개별적으로 펼 처서 복사하거나 전달하려면... 배열이나... 객체 사용(spread연산자)

 

let members2 = [
    ...members,
    "신지원"
]

수정하거나 데이터 추가할 때도 편리하다.

let choi = {
    name: "jiwon",
    age: 24,
    gender: "남"
};

//값을 수정할 때
choi = {
    ...choi,
    gender: "여"
};
console.log(choi);

//데이터를 추가할 때
choi = {
    ...choi,
    address: "경기도 광명시"
}
console.log(choi);

 

비구조할당

배열이나 객체에서 값을 추출할 때 개별변수에 할당해서 추출하는 문법

const [cho, lee, kim] = members;
console.log(cho, lee, kim);

choi = {
    name: "jiwon",
    age: 24,
    gender: "남"
};

const {name, age} = choi;
console.log(name);
console.log(age);

const {name:userName, age:userAge} = choi;
console.log(userName);
console.log(userAge);

sql의 서브쿼리가 복수인 다중열처럼 가능하다.

 

JS반복문

1. 기본 반복문

for(let i=0; i<stdList.length; i++){
    console.log(stdList[i]);
}

 

2. for of

배열 값 중심으로 순회한다. 가장 깔끔하며 인덱스가 필요 없을 때 사용.

for(const std of stdList){
    console.log(std);
}

 

3.for in

인덱스 중심으로 순회한다.

for(const i in stdList){
    console.log(i + "번째 : ", stdList[i]);
}

객체의 key를 전부 열거하는 법

const std = {name: "최지원", java: 75, db: 80, front: 90};
for(const key in std){
    console.log(key);
}

 

배열의 고차함수

읽기 전용 + 새로운 배열/값을 반환 -> 불변경 유지를 위해
배열.forEach(function(v: 순차적으로 요소하나, i: 인덱스번호, a: 전체배열){}

stdList.forEach(function(v, i, a){
    console.log(v, " ",  i, " ", a);
});

'JS' 카테고리의 다른 글

JS 4일차  (0) 2025.09.23
JS 3일차(2)  (0) 2025.09.22
JS 2일차(2)  (2) 2025.09.19
JS 2일차(1)  (0) 2025.09.19
JS 1일차(2)  (0) 2025.09.17