Develop

22일차_Front(JS-Function, Callback, Closure, Constructor, this, Blocking vs Non-Blocking 등) 본문

백엔드/KDT_Programmers

22일차_Front(JS-Function, Callback, Closure, Constructor, this, Blocking vs Non-Blocking 등)

230801 2025. 4. 3. 01:05

안녕하세요~!

오늘은 자바스크립트 문법에 대해 더 배웠습니다~~

 

자바와 비슷해서 대충은 알아듣겠는데 코드를 보면 이게 뭘 바라보고 있는지 금방떠오르지 않더라구요.

오늘은 그런내용이 주를 이뤘던것 같아 평소보다 시간을 들여 학습했습니다. (오늘 분량 많음..ㄷㄷ)

 

내일은 DOM, 브라우저에 적용한다길래 좀 더 확실히 공부하려고 했던 부분도 있습니다... 두려워 ~

 

 


 

Java Script에서의 함수

  • 함수는 객체지만, 일반 객체와 다름
    • 함수는 호출할 수 있고, 일반객체에는 없는 함수 객체만의 고유한 프로퍼티를 가짐
  • 변수 f 에 함수 리터럴을 할당
    • 리터럴 : 사람이 이해할 수 있는 문자 또는 약속된 기호를 사용해 값을 생성하는 표기방식
    • 함수 리터럴 : function 키워드, 함수이름, 매개변수 목록, 함수 몸체

 const f = function add(x, y) {
	return x + y;
};

 

함수 정의 (4가지 방법)

  1. 함수 선언문
    • 코드가 해석되기 전에 메모리에 등록됨 (호이스팅 가능)
    • 전역 스코프에서 사용
    function add(x, y) {
    	return x + y;
    };
    
  2. 함수 표현식
    • 익명함수(함수 리터럴)를 변수에 대입해서 작성
    • 표현식이라서 초기화 전에는 못씀(호이스팅 불가)
    • 콜백 등에서 사용
    const add = function (x, y) {
    	return x + y;
    };
    
  3. Function 생성자 함수
    • 문자열 기반으로 매개변수와 함수분문 작성
    • 동적 생성 : 런타임에 함수를 생성
    • 느림 : 파싱을 한번 더 해서 성능 떨어짐
    • scope : 글로벌 스코프 기준(로컬 스코프 못씀)
    const add = new Function('x', 'y', 'return x + y');
    
  4. 화살표 함수 (ES6)
    • 매개변수 ⇒ 실행할 코드(반환값) 구조로 작성
    const add = (x, y) => x + y;
    

 

Callback 함수

  • 다른 함수에 인자로 전달되어, 특정시점에 호출되는 함수
    • 작업이 끝난 후 어떻게 처리할지 외부에서 정의
    • 그 후의 행동을 유연하게 바꿀 수 있어서 확장성이 있음
    • 비동기 환경에서 코드 순서와 흐름을 안전하게 컨트롤하기 위해 도입된 개념
  • 예제 - 유저 로그인 후, 후처리 콜백 실행

  • 용도
    1. 비동기 작업 끝난 후 실행 (서버 요청, 파일 읽기, 타이머 등)
    2. 순서 보장 (작업 끝나고 나서 다음작업 실행)
    3. 이벤트 처리 (유저가 클릭하거나 입력했을때 실행할 함수 등록)
function loginUser(username, onSuccess) {
  console.log(`${username}님 로그인 중...`);
  
  setTimeout(() => {
    console.log(`${username}님 로그인 완료!`);
    onSuccess(); // 콜백 실행
  }, 1000); // 로그인 시뮬레이션 (1초 후 성공)
}

// 사용자가 로그인 후에 메시지 팝업을 띄워줌
loginUser('홍길동', function (user) {
  alert(`${user.name}님, 오늘도 반갑습니다!`);
});

 

Closure (클로저)

  • 함수가 선언될 당시의 외부 변수 환경(스코프)를 기억하는 함수
    • 이미 실행이 끝난 외부 함수의 변수도 내부함수가 계속 접근할 수 있게 해주는 기능
  • 클로저 생성
    • 함수 returnFnc()는 실행이 끝났지만
    • 내부의 return function이 클로저로서 count를 기억하고 있기때문에
    • 외부의 변수 fn이 클로저(return된 함수)를 포함하고 있기 때문에 count에 접근 가능함

function returnFnc() {
  let count = 0;
  return function () {  // 클로저 생성
    count++;
    console.log(`count: ${count}`);
  };
}

const fn = returnFnc(); // 클로저를 담고있는 변수
fn();  // count : 1
fn();  // count : 2

 

실행방식에 따른 클로저 초기화 비교

  1. returnFnc()();
    • 매번 클로저를 새로 만들고 바로 실행 → 상태 유지 안됨

  2. returnFnc();returnFnc();
    • 리턴만 하고 실행 안함 → 클로저는 생성되지만 사용되지 않음
      • 서로 다른 클로저 → 상태 공유 안됨
      returnFnc();  // count: 1 (미출력, 내부 함수 리턴만 하고 실행 안 됨)
      returnFnc();  // count: 2 (미출력, 또 리턴만 함)
      
  3. const fn = returnFnc(); fn(); fn()
    • 변수에 저장 후 실행 → 상태 기억하는 클로저 활용
    • const fn = returnFnc(); fn(); // count: 1 (출력) fn(); // count: 2 (출력)
returnFnc()(); // count: 1 (출력)
returnFnc()(); // count: 1 (출력, 매번 함수만들고 바로실행 -> 클로저 상태 초기화됨)

 

IIFE (즉시 실행 함수 표현식, Immediately Invoked Function Expression)

  • 함수의 선언과 동시에 실행
    • 용도 : 주로 일회용 함수를 만들 때 사용
    • 구조 : 함수 선언문 전체를 괄호로 감싸고, 끝에서 ()로 함수를 실행해줌
(function iife(){
  console.log('선언과 동시에 실행')
})();

 

  • 함수 선언문 전체를 ()로 감싸는 이유
    • function 키워드가 맨앞에 있으면 함수 선언문이라고 해석할 여지가 있기 때문에 전체를 괄호로 감싸서 표현식으로 만듦
  • 괄호로 감싸지 않고 쓸 수 있는 방법 : 자바스크립트가 표현식으로 인식할 수 있게 기호를 붙여줌표현식 만드는 방법예시 
  •  
    괄호로 감싸기 (function () {})()
    ! 붙이기 !function () {}()
    + 붙이기 +function () {}()
    ~, -, void 등 ~function () {}()

 

Constructor Function

prototype 과 __proto__ 속성의 차이점

  1. prototype
    • 생성자 함수에서 쓰임
    • 생성자 함수의 속성
    • 새로 생성될 객체가 참조할 프로토타입 객체를 가리킴
      • 함수입장에서 내가 낳을 자식의 부모
  2. __proto__
    • 내부적으로 동작, prototype chain용
    • 일반객체의 속성
    • 객체가 참조하는 실제 프로토타입
      • 객체입장에서 내 부모(prototype)

 

proto chain

  • 객체가 가진 속성이 없을 때 proto 로 따라 올라가서 계속 찾는 구조

 


this 사용방식

 

1. 전역에서의 this

  • 전역 스코프에서 this를 호출하면 전역 객체를 가리킨다.
  • (브라우저: window, Node.js: global)

 

2. 일반 함수에서의 this

  • 함수 내부에서 this를 사용하면 전역 객체를 가리킨다.
  • (strict mode에서는 undefined)

 

3. 메서드에서의 this

  • 객체의 메서드에서 this는 그 메서드를 호출한 객체 자신을 가리킨다.

 

4. 생성자 함수에서의 this

  • 생성자 함수 내의 this는 새로 만들어지는 인스턴스 객체를 가리킨다.
  • (new 키워드로 생성된 객체)

 

5. 화살표 함수에서의 this

  • 화살표 함수는 자신만의 this를 가지지 않고,
  • 선언된 위치의 상위 스코프의 this를 그대로 따른다.
  • 따라서 메서드나 명시적 this 바인딩에서는 사용하지 않는 것이 좋다.

 

6. 명시적 this 바인딩 (call, apply, bind)

  • call, apply, bind를 사용하면
  • 함수의 this를 명시적으로 특정 객체로 바인딩할 수 있다.

 

Blocking vs Non-Blocking

Blocking (제어권 없음)

  • 작업이 끝날 때까지 현재 스레드가 멈춰서 대기한다.
  • 다른 작업을 수행할 수 없고, 제어권이 작업 처리 주체에게 있다.

 

Non-Blocking (제어권 있음)

  • 요청만 보내고 기다리지 않는다.
  • 다른 작업을 계속 수행할 수 있으며, 제어권을 호출한 쪽이 유지한다.

 

Java Connection Pool 예시 (Blocking)

  • 예를 들어, take() 메서드가 호출될 때 리소스가 없다면, 해당 스레드는 대기 상태로 전환된다.
  • BlockingQueue는 내부적으로 접근한 스레드를 재운다.
  • 외부에서 리소스를 반납하면, 잠든 스레드가 깨어나 작업을 수행한다.
  • 제어권은 Connection Pool이 가지고 있다.
  • LinkedBlockingQueue 등도 같은 방식으로 동작한다.

 

JavaScript는 Non-Blocking

  • 병렬 작업을 브라우저나 런타임에 위임하고, 나머지 코드를 계속 수행한다.
  • 제어권을 유지하면서 다음 작업을 처리할 수 있기 때문에 Non-Blocking 이다.

비동기로 실행되는 함수가 끝나는 시점과, 다음 로직이 시작되는 시점을 맞추지 않음 여러개의 비동기 작업 중 작업순서를 맞춰야하는 경우, callback 함수 안에서 다음 수행해야할 비동기작업을 시작 =>  callback hell 이슈가 발생

 

 

 

 

 

오늘도 수고 많으셨습니다 !