파크로그
article thumbnail

함수와 클로저(closure)

스코프

  • 함수 선언식으로 만들어진 함수는 함수 레벨 스코프를 갖는다.
  • var 또한 함수 레벨 스코프
    • let, const 는 블록 레벨 스코프
    // 함수 선언문 -> 함수 호이스팅
    function foo(){
    }
    // 함수 표현 식 -> 변수 호이스팅
    const foo = function() {
    }
    
    function foo() {
    	if(true) {
    		var color = 'blue';
    	}
    	console.log(color); // blue
    }
    console.log(color); // color is not defined
    foo();
    
    function bar() {
    	if(true) {
    		let color = 'blue';
    	}
    	console.log(color); // Reference error : color is not defined
    }
    bar()
  • varletconst 로 대체가 가능하며, var 자체의 스코프가 다르기 때문에 혼란을 야기하여 var 을 사용하지 않는다.
 

  • 스코프는 함수를 실행 할 때가 아닌 선언 할 때 생긴다.

함수 vs 클로저(Closure)

  • 함수 + 함수를 둘러싼 환경(Lexical environment) : 렉시컬 스코프
  • 함수가 생성되는 시점에 생성 → 생성될 때 그 함수의 렉시컬 환경을 포섭(closure)
  • 자바스크립트의 모든 함수는 상위 스코프(global 포함) 을 기억하므로 함수 + 렉시컬 환경 의 조합이 성립하고, 이론적으로는 모든 함수는 클로저 이지만 일반적으로 모든 함수를 클로저 라고 부르지는 않는다.
    • 상위 스코프의 어떠한 식별자도 참조하지 않는 함수는 클로저가 아니다
    • 대부분의 모던 브라우저는 상위 스코프의 어떤 식별자도 참조하지 않는 경우 상위 스코프를 기억하지 않는다.
      • 상위 스코프가 Block ?
function foo() {
	var color = 'blue';
	function bar() {
		console.log(color);
	}
	bar();
}
foo();
  • bar() : foo() 안에 속하기 때문에 foo 스코프를 외부 스코프로 참조
    • bar는 자신의 렉시컬 스코프 체인을 통해 foo  color를 참조
    • bar 는 클로저인가?
      • bar  foo 안에서 정의되고 실행 되었을 뿐, foo 밖으로 나오지 않았기 때문에 클로저라고 부르지 않는다.
var color = "red";
function foo() {
	var color = "blue"; // 2
	function bar() {
		console.log(color); // 1
	}
	return bar;
}
var baz = foo(); // 3
baz(); // 4
  1. bar  color 를 찾아 출력하는 함수로 선언
  1. bar 는 외부 환경 참조로 foo 의 환경을 외부 스코프로 참조
  1. bar  global  baz 란 이름으로 데려옴 → return bar
  1. global 에서 baz(=bar)를 호출
  • bar는 자신의 스코프에서 color 를 찾는다
    • 없기 때문에 외부 환경 참조를 찾아간다 (foo 의 환경)
    • foo 환경에서 var color = "blue" 를 찾았으므로, blue 를 출력한다.

 

  • bar 는 자신이 생성된 렉시컬 스코프에서 벗어나 global 환경에서 baz 라는 이름으로 호출되어 스코프 탐색으로 현재 실행 스택과 관련 없는 foo 를 거쳐갔다.
  • bar 의 생성과 직접적인 관련이 없는 global 환경 에서 호출 해도 bar 의 외부 참조환경인 foo 에서 color 를 찾음
  • Javascript 의 스코프는 렉시컬 스코프, 이름의 범위는 소스코드가 작성된 그 문맥에서 바로 결정되는 것
    • foo  렉시컬 환경은 foo(); 수행이 끝난 후 GC 가 회수?
      • bar  foo 의 렉시컬 환경을 참조하고 있기 때문에 회수하지 않는다.
      • foo 함수의 실행 컨텍스트는 스택에서 제거된다.

클로저 선언이나 축약 표현

const addFunc = function(a) {
	return function(b) {
		return a+b;
	}
}
const add3 = addFunc(3)
add3(5) // return 8

// add3 은 아래처럼 작동
const add3 = function() {
	const a = 3
	return function(b) { 
		return a+b
	}
}
// 함수를 실행할 때 (addFunc3) 새로운 렉시컬 환경이 만들어짐
// 해당 환경엔 매개변수(a)와 함수의 지역함수가 저장됨
// 매개변수(3) 이 저장된 것과 함수의 지역함수(const a=3) 이 저장된 것이 같다고 할 수 있음

축약

const addFunc = a => b => a+b
const add3 = addFunc(3)
add3(5) // return 8

// Currying
addFunc(2)(8) // return 10

 

참고

profile

파크로그

@파크park

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!