스코프(Scope)와 클로져(Closure)
📍 스코프란?
- 스코프(scope)는 '범위'라는 뜻!
- 컴퓨터공학에서 스코프는 '변수의 유효범위'라는 의미로 사용된다.
예를 들어..
let greeting = 'Hello';
function greetSomeone() {
let firstName = 'Josh';
return greeting + ' ' + firstName;
}
greetSomeone(); // 'Hellow Josh'
firstName; // Uncaught ReferenceError: firstName is not defined
- Local Scope(변수 firstName에 접근할 수 있는 범위)에 선언된 변수는 함수 밖(Global Scope)에서는 참조할 수 없다.
- 즉, 함수 밖에서 greetSomeone 함수 안에 정의되어있는 firstName 변수에 접근할 수 없다!
Basics
- Scope는 "변수 접근 규칙에 따른 유효 범위"이다. 즉, 변수와 그 값이 어디서부터 어디까지 유효한지 판단하는 범위를 말한다.
- 변수는 어떠한 환경 내에서만 사용 가능하며, 모든 프로그래밍 언어는 각각의 변수 접근 규칙을 갖고 있다. JavaScript는 기본적으로, 함수가 선언되는(lexical) 동시에 자신만의 Scope를 가진다.
RULE #1: Local Scope vs. Global Scope
- 안쪽 Scope에서 바깥 변수/함수를 접근하는 것은 가능
- 바깥 Scope에서 안쪽 변수/함수를 접근하는 것은 불가능
- Scope는 중첩이 가능하다 (= 함수 안에 함수를 넣을 수 있다)
- Global Scope는 최상단의 Scope로 여기서 정의된 변수(전역변수)는 어디서든지 접근이 가능하다
- 지역변수는 함수 내에서 전역변수보다 더 높은 우선순위를 가진다
ex)
let name = 'Richard';
function showName() {
let name = 'Jack' //지역변수, 전역에서 선언한 name과는 다른 변수!!
console.log(name); //Jack (지역변수가 전역변수보다 우선시되므로)
}
console.log(name); //Richard
showName();
console.log(name); //Richard
RULE #2: Function Scope vs. Block Scope
- block: 중괄호(curly bracket, {})로 시작하고 끝나는 단위
- 변수를 정의하는 키워드 (var 키워드 vs. let 키워드)
1) var 키워드(old way)
JavaScript는 기본적으로 함수 단위로 자신만의 Scope를 가진다
2) let 키워드
그러나, Block 단위로 Scope를 구분했을 때에 예측하기 쉬운 코드를 작성할 수 있다. let 키워드를 썼을 때는 block의 영역 안에서만 사용할 수 있기 때문!
for(var i = 0; i < 5; i++) {
console.log(i); //5번 iteration
}
console.log('final i:', i); //5
- block 범위를 벗어나도 (같은 function scope 에서는) i를 사용할 수 있다. 위 코드에서는 function 구분이 없으므로 이 자체로 하나의 function scope를 갖고 있다. 따라서 block을 벗어나도 i를 사용할 수 있다.
- i 가 4 가 아닌 5인 이유는 증감문까지 반복하기 때문이다
- var 대신 let으로 선언하면 i를 중괄호 안의 영역에서만 사용할 수 있으므로 ReferenceError가 뜬다!
- 예상 못하게 i를 뒤에서도 재사용할 위험성이 있으므로 var보다는 let을 쓰는 것을 추천!
3) const 키워드
- constant의 줄임말
- 값이 변하지 않는 변수, 즉 상수를 정의할 때 사용하는 키워드
- let 키워드와 동일하게 block scope를 따른다
- 값을 재할당하려고 하면 TypeError를 낸다. 따라서 값이 변하지 않길 원하는 경우에 const를 사용하면 좋다 (ex. const pi = 3.14)
<키워드 비교 정리>
- 재선언: var, let, const (불가능)
- 재할당: var, let (가능) const (불가능)
- 유효범위: var(function) let, const (block)
실제 코딩을 할 때 재선언을 하게 되는 경우는 대게 버그이다. 따라서 let 과 const는 이러한 실수를 막아준다.
RULE #3: 전역 변수와 window 객체
- window 객체는 Global Scope를 대표하는 객체
- Global Scope(전역범위)에서 선언된 함수와 var 키워드를 이용해 선언된 변수는 window 객체와 연결된다 (let 키워드로 선언된 변수는 window 객체에 담기지 않는다)
var myName = 'Paul';
console.log(window.myName); //Paul
- 전역범위에 너무 많은 변수를 선언하지 않도록 주의!!
- 전역범위는 최상위 스코프인 만큼 어떤 프로그램이 어떤 변수를 사용할지 모르므로, 전역범위보다는 하나의 scope를 만들어서 그 안쪽에서 변수를 선언하고 사용하는 것이 좋다
- TIP! 작성하는 자바스크립트 프로그램에 {}을 열고 그 안에 let이라는 키워드를 이용해 변수를 선언한다면 안전하게 작성한 코드를 이용할 수 있다
RULE #4: 선언 없이 초기화된 전역 변수의 위험성
- 절대로! 선언 키워드 (var, let, const) 없이 변수를 초기화하지 말자
function showAge () {
age = 90; // age는 전역변수로 취급!
console.log(age);
}
showAge(); //90
console.log(age); //90
- age를 선언하지 않았을 경우 error가 뜨는 대신 이를 전역변수로 취급한다 (age === window.age)
- 따라서 scope 밖에서도 age를 사용할 수 있다. 좋은 것 아님! 주의!
- 'use strict';
위와 같은 실수를 방지하고 싶을 경우, Strict Mode를 사용할 수 있다.
'use strict'라는 문자열을 자바스크립트 파일 맨 상단에다가 넣으면 Strict Mode를 사용할 수 있다.
Strict Mode를 적용할 경우 문법적으로 실수(ex. 변수선언을 키워드 없이 함)할 수 있는 부분들을 에러로 판단한다.
구글 개발자 도구에서는 적용이 안되고, 파일을 저장해야 가능하다.
2. Closure
" 클로저는 함수와 함수가 선언된 어휘적(lexical) 환경의 조합을 말한다. 이 환경은 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다."
- 함수가 호출되는 환경과 별개로 기존에 선언되어 있던 환경(어휘적 환경)을 기준으로 변수를 조회하려고 한다.
- 외부함수의 변수에 접근할 수 있는 내부함수를 클로저 함수라고 부르기도 한다
- 다른 컴퓨터 언어와는 다른 자바스크립트의 특성 중 하나
유용한 클로저 예제
1) 커링
: 함수 하나가 n개의 인자를 받는 대신, n개의 함수를 만들어 각각 인자를 받게 하는 방법
function adder(x) {
return function(y) {
return x+y;
}
}
adder(2)(3); // 5
x값을 고정해놓고 재사용할 수 있다!
let add100 = adder(100);
add100(2); //102
add100(10); //110
adder라는 함수는 함수를 생성해주는 함수!
2) 외부 함수의 변수를 이너 함수가 계속 재사용하면서 마치 템플릿 함수와 같이 사용 가능
3) 클로저 모듈 패턴
: 변수를 스코프 안쪽에 가두어 함수 밖으로 노출시키지 않는 방법
function makeCounter() {
let privateCounter = 0;
return {
increment: function() {
privateCounter ++;
},
decrement: function() {
privateCOunter--;
},
getValue: function() {
return privateCounter;
}
}
}
let counter1 = makeCounter();
counter1.increment();
counter1.increment();
counter1.getValue(); // 2
let counter2 = makeCounter();
counter2.increment();
counter2.decrement();
counter2.increment();
counter2.getValue(); // 1
privateCounter; //ReferenceError
- 두 counter에 각각 독립적으로 privateCounter를 가지고 있다!! 따라서 counter2의 실행이 counter1에 영향을 미치지 않는다
- 스코프 밖에서 privateCounter의 값을 건드릴 수 없다! 오직 increment, decrement와 같은 함수를 통해 간접적으로 privateCounter 값을 바꿀 수 있다
Self-Check
Scope
- JavaScript의 Scope의 의미와 적용 범위를 이해할 수 있다
- JavaScript의 Scope 주요 규칙을 이해할 수 있다
< 중첩 규칙
< block scope(block-level scope) vs. function scope(function-level scope)
< let, const, var의 차이
< 전역 변수와 전역 객체의 의미Closure
- Closure의 정의와 특징에 대해서 이해할 수 있다.
- Closure를 활용해서 외부함수의 변수에 접근할 수 있다.
- Closure의 유용하게 쓰이는 몇 가지 코딩 패턴을 이해할 수 있다
Author And Source
이 문제에 관하여(스코프(Scope)와 클로져(Closure)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@franchesca/Scope-Closure-92a5ryyw저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)