본문 바로가기

자바스크립트/기초

스코프와 클로저

스코프

범위가 중괄호(블록) 또는 함수에 의해 나뉘어지고, 그 범위를 스코프라고 부릅니다.

변수 접근 규칙에 따른 유효 범위로 사용합니다. 프로그래밍 언어에서 유효범위는 어느 범위까지 참조하는 지를 뜻합니다.

유효 범위의 종류에는 크게 두 가지가 있습니다.

  • 전역 스코프 (Global scope) : 스크립트 전체에서 참조되는 것을 의미하며, 어느 곳에서든 참조 됩니다.
  • 지역 스코프 (Local scope) : 정의된 함수 내에서만 참조되는 것을 의미하며, 밖에서는 참조 되지 않습니다.

스코프의 규칙 

1.

바깥쪽 스코프에서 선언한 변수는 안쪽 스코프에서 사용 가능합니다.

반면에, 안쪽에서 선언한 변수는 바깥쪽 스코프에서는 사용할 수 없습니다.

2.

스코프는 중첩이 가능합니다. 스코프는 마치 중첩된 울타리와 같습니다.

특별히 가장 바깥쪽의 스코프는 전역 스코프(Global Scope)라고 부릅니다. 전역의 반대말은 지역으로 전역이 아닌 다른 스코프는 전부 지역 스코프(local scope)입니다.

엔진은 현재 스코프에서 변수를 찾기 시작하고, 찾지 못하면 한단계 씩 올라갑니다.
최상위 글로벌 스코프에 도달하면 변수를 찾았든, 못 찾았든 검색을 멈춥니다.

 

3.

지역 변수는 전역 변수보다 더 높은 우선순위를 가집니다.

스코프의 종류

스코프의 종류는 두가지가 있습니다.

블록 스코프(block scope): 중괄호로 둘러싼 범위

함수 스코프(function scope): 함수로 둘러싼 범위

 

* 화살표 함수는 블록 스코프로 취급됩니다

let, const, var

var 키워드로 정의한 변수는 만들어낸 블록 스코프를 무시하고, 함수 스코프만 따릅니다. (화살표 함수의 블록 스코프는 무시하지 않습니다.) 함수 스코프는 함수의 실행부터 종료까지이고, var 선언은 함수 스코프의 최상단에 선언됩니다. 선언 키워드 없는 선언은 최고 스코프에 선언됩니다. 함수 내에 선언 키워드 없는 선언은 함수의 실행 전까지 선언되지 않은 것으로 취급합니다.

 

보통 코드를 작성할 때 블록은 들여쓰기가 적용되고, 그 구분이 시각적으로 분명합니다. 따라서 많은 사람들은 블록 스코프를 기준으로 코드를 작성하고, 생각하기 마련입니다. 그러나 var는 이 규칙을 무시하므로, 코드를 작성하는 사람이 블록 스코프/함수 스코프에 대한 이해가 없으면 코드가 다소 혼란스러울 수 있습니다. 따라서, var 보다는 let 으로 변수 선언을 하는 것을 권장합니다.

 

var 키워드보다 let 키워드가 안전한 이유는 또 있습니다. let 키워드는 재선언을 방지합니다. 실제로 코딩할 때에 변수를 재선언해야 할 필요가 있을까요? 대부분 이런 경우는 버그입니다.

 

const 라는 키워드도 있습니다. 변하지 않는 값, 곧 상수(constant)를 정의할 때에는 const를 이용합니다. const는 값의 재할당이 불가능합니다. 값을 재할당할 경우 TypeError를 내므로, 의도하지 않은 값의 변경을 막을 수 있습니다.

 

  let const var
유효 범위 블록 스코프 및 함수 스코프 블록 스코프 및 함수 스코프 함수 스코프
값 재할당 가능  불가능 가능
재선언 불가능 불가능 가능

 

Window 객체

window 객체는 사실 브라우저의 창(window)을 의미하는 객체이지만, 이와 별개로 전역 영역을 담고 있기도 합니다. 함수 선언식으로 함수를 선언하거나, var로 전역 변수를 만들면, window 객체에서도 동일한 값을 찾을 수가 있습니다.

 

전역 변수는 가장 바깥 스코프에 정의한 변수입니다. 따라서, 어디서든 접근이 가능합니다. 얼핏 "모든 변수를 바깥으로 빼면 스코프 걱정을 하지 않아도 되겠네?" 라는 생각이 들 수도 있습니다. 그러나, 전역 변수를 많이 만드는 것은 그다지 좋은 선택이 아닙니다. 보통 애플리케이션을 만들 때에는, 내가 직접 작성하지 않은 수많은 다른 함수와 로직이 포함됩니다. 너도나도 똑같은 이름으로 전역 변수를 선언하려고 한다면 분명 문제가 발생할 것입니다. 이를 side effect라고 합니다. 전역 변수를 최소화하는 것은 side effect를 줄이는 좋은 방법입니다.

 

앞서 배웠듯, var 키워드는 블록 스코프를 무시합니다. 또한 재선언을 해도 에러를 내지 않습니다. 따라서, let과 const를 주로 사용하세요. 전역 변수를 var로 선언하는 것은 브라우저의 내장 기능을 사용하지 못하게 만들 수도 있습니다.

 

선언 없이 변수를 할당하지 마세요. 선언 없이 변수를 할당하면, 해당 변수는 var로 선언한 전역 변수처럼 취급됩니다.

 

사실 이런 것은 애초에 브라우저에서 방지해준다면 더 안전하게 코드를 작성할 수 있을 것입니다. Strict Mode는 브라우저가 보다 엄격하게 작동하도록 만들어줍니다. 앞서 언급한 것처럼 "선언 없는 변수 할당"의 경우도 Strict Mode는 에러로 판단합니다. Strict Mode를 적용하려면, js 파일 상단에 'use strict' 라고 입력하면 됩니다. (따옴표 포함)

 

전역 범위를 대표하는 객체 Window
Global Scope에서 선언된 함수, 그리고 var 키워드를 이용해 선언된 변수는 window 객체와 연결된다. 단, 전역 범위에 너무 많은 변수를 선언하지 않도록 주의하자!

 

var myName = 'scopie'; 
console.log(window.myName); //scopie
function foo(){
  console.log('bar');
}
console.log(foo === window.foo); //true

클로저

A closure is the combination of a function and the lexical environment within which that function was declared. This environment consists of any local variables that were in-scope at the time the closure was created.

 

클로저는 함수와 함수가 선언된 어휘적 환경의 조합을 말합니다.

이 환경은 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성됩니다.

 

여기서의 키워드는 "함수가 선언"된 "어휘적(lexical) 환경"입니다.

특이하게도 자바스크립트는 함수가 호출되는 환경와 별개로, 기존에 선언되어 있던 환경 - 어휘적 환경 - 을 기준으로 변수를 조회하려고 합니다.

 

클로저 함수: 외부 함수의 변수에 접근할 수 있는 내부 함수 , 함수를 리턴하는 함수

 

클로저는 리턴하는 함수에 의해 스코프(변수의 접근 범위)가 구분된다. 클로저의 핵심은 스코프를 이용해서, 변수의 접근 범위를 닫는(closure: 폐쇄) 데에 있다. 따라서 함수를 리턴하는 것 만큼이나, 변수가 선언된 곳이 중요하다.

 

실용적인 클로저

클로저는 어떤 데이터(어휘적 환경)와 그 데이터를 조작하는 함수를 연관시켜주기 때문에 유용하다. 이것은 객체가 어떤 데이터와(그 객체의 속성) 하나 혹은 그 이상의 메소드들을 연관시킨다는 점에서 객체지향 프로그래밍과 분명히 같은 맥락에 있다.

결론적으로 오직 하나의 메소드를 가지고 있는 객체를 일반적으로 사용하는 모든 곳에 클로저를 사용할 수 있다.

이렇게 할 수 있는 상황은 특히 웹에서 일반적이다. 프론트 엔드 자바스크립트에서 우리가 쓰는 많은 코드가 이벤트 기반이다. 우리는 몇 가지 동작을 정의한 다음 사용자에 의한 이벤트에(클릭 혹은 키 누르기 같은) 연결한다. 우리의 코드는 일반적으로 콜백으로 첨부된다: 이벤트에 응답하여 실행되는 단일 함수다.

예를 들면 페이지의 글자 크기를 조정하는 몇 개의 버튼을 추가한다고 가정하자. 이 작업을 수행하는 한 가지 방법은 body 요소의 font-size를 픽셀 단위로 지정하고 상대적인 em 단위를 사용하여 페이지의 다른 요소들의 (예: 헤더) 크기를 설정하는 것이다.

출처: https://developer.mozilla.org/ko/docs/Web/JavaScript/Closures

 

클로저 - JavaScript | MDN

클로저는 함수와 함수가 선언된 어휘적 환경의 조합이다. 클로저를 이해하려면 자바스크립트가 어떻게 변수의 유효범위를 지정하는지(Lexical scoping)를 먼저 이해해야 한다.

developer.mozilla.org

스코프 - 2배율로는 8배율로 못쓴다

클로저 - 자물쇠로 잠구기, 밖이 투명하게 보이는 화장실 안

 

function factories

namespacing private variables/functions

검색 후 다시 보려고 기록하는 사이트들

https://ui.toast.com/weekly-pick/ko_20160905

 

자바스크립트에서 팩토리 함수란 무엇인가? | TOAST UI :: Make Your Web Delicious!

자바스크립트에서 팩토리 함수란 무엇인가? 원문: https://www.sitepoint.com/factory-functions-javascript/ 이 아티클은 Jeff Mott가 검토하였다. SitePoint 컨텐츠를 만들기 위해 최선을 다해준 모든 SitePoint 리뷰어

ui.toast.com

https://jdm.kr/blog/118

 

자바스크립트 네임스페이스(javascript namespace) :: JDM's Blog

자바스크립트는 변수의 선언 및 자용이 자유롭고 느슨합니다. 빠른 프로토타이핑을 가능하게 하고 반대로 디버깅을 할 때 미치게 만드는 요소이기도 합니다. 개인적으로는 작업할 때 간단한 로

jdm.kr

 

반응형