Scope & Closure

future·2021년 1월 10일
0

JavaScript

목록 보기
2/10

Scope란?

변수에 접근할 수 있는 유효범위이다.
코드가 어디까지 잘 작동하고 있는지 알아야 하기 위해 사용한다.

🔖 Scope의 적용 범위

1. 전역 변수 (Global scope)

  • 전역 변수는 최상단 scope로 어디에서든 참조 가능하다.
let x = 'global';

function foo() {
  let y = 'local';
  console.log(x);
  console.log(y);
}

foo();			// global, local
console.log(x);		// global
console.log(y);		// Uncaught ReferenceError
  • ReferenceError : global에서는 local을 참조할 수 없다는 의미

2. 지역 변수 (Local scope)

  • 지역 변수는 함수 내에서 전역 변수보다 더 높은 우선순위를 가진다.
let x = 'global';

function foo() {
  x = 'local';
  return x;
}

foo();			// local
console.log(x);		// local

✔️ local에서 global 함수/변수에 접근하는 것은 가능하다.
✔️ global에서 local 함수/변수에 접근하는 것은 불가능하다.
✔️ Scope는 함수 안에 함수를 넣을 수 있다.

👉 Scope의 적용 범위 예시

① local scope 안에 변수를 선언해주는 경우

let greeting = 'good morning';

function letsGreet() {
  let greeting = 'good night';
  console.log(greeting);	// 2 good night
}

console.log(greeting);		// 1 good morning
letsGreet();		
console.log(greeting);		// 3 good morning
  • letsGreet()가 실행된다고 해도 마지막 전역변수는 영향을 받지 않는다.

② local scope 안에 변수를 선언하지 않는 경우

let greeting = 'good morning';

function letsGreet() {
  greeting = 'good night';
  console.log(greeting);	// good night
}

console.log(greeting);		// good morning
letsGreet();
console.log(greeting);		// good night

🔖 Function Scope & Block Scope

1. Function Scope

for (var i = 0; i < 3; i++) {
  console.log(i);	// 0, 1, 2
}
console.log(i);		// 3
  • var로 변수를 선언할 경우 block의 범위를 벗어나더라도 function 내에서 사용이 가능하다.

2. Block Scope

for (let i = 0; i < 3; i++) {
  console.log(i);	// 0, 1, 2
}
console.log(i);		// ReferenceError
  • let으로 변수를 선언할 경우 block 내에서만 사용이 가능하다.

🔖 let / const / var 의 차이

  • 반복문처럼 값이 재정의 되는 경우에는 let을 사용한다.
  • 그 외에는 보통 const를 사용하는 경우가 많다.
  • var를 사용할 경우 재선언이 가능하지만, 실제로 코딩할 때 재선언 하는 경우는 버그일 가능성이 높기 때문에 권장되지 않는다.

🔖 전역 변수와 window 객체

  • 전역(global scope)에서 선언된 함수와 var 키워드를 통해 선언된 변수는 window 객체에 들어간다.
function greeting() {
  console.log('hello');
}

greeting === window.greeting
var symbol = '8ball';

symbol === window.symbol

🔖 선언 없이 초기화된 전역 변수

  • 절대 선언 키워드 없이 변수를 초기화해서는 안 된다.
  • 변수 선언을 하지 않을 경우, 어떤 scope에서든 전역 변수가 되기 때문에 오류를 발생시킬 수 있다.
  • 그래서 코드 내의 문법적인 오류를 방지하기 위해 Strict Mode('use strict')를 사용한다.
  • Strict Mode는 저장된 파일에서만 사용할 수 있다. (개발자도구 콘솔창 X)

Closure란?

  • 외부 함수의 변수에 접근할 수 있는 내부 함수이다.
  • 클로저는 함수와 함수가 선언된 어휘적 환경의 조합을 말한다.
  • 이 환경은 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다.

🔖 Closure를 활용해서 외부함수의 변수에 접근하는 법

function outerFn() {
  let outerVar = 'outer';	// 외부 함수의 변수
  console.log(outerVar);

  function innerFn() {		← 클로저 함수
    let innerVar = 'inner';	// 지역 변수
    console.log(innerVar);
  }
  return innerFn;
}

let globalVar = 'global';	// 전역 변수

outerFn()();			// outer , inner
let innerFn = outerFn();	// outer
innerFn();			// inner
  • 클로저 함수 안에서는 아래 변수의 접근이 전부 가능하다.
    ✔️ 지역 변수 innerVar
    ✔️ 외부 함수의 변수 outerVar
    ✔️ 전역 변수 globalVar

👉 Closure 함수의 예시

let add = function(x) {
  let sum = function(y) {	← 클로저 함수
    return x + y;
  }
  return sum;
}

let foo = add(1);
foo(3);
let total = foo(6);		// 7
  • 함수 addx를 매개변수로 하고 함수 sum을 반환한다.
  • add는 매개변수 x를 통해 전달받은 값을 내부함수 sum에게 내려준다.
  • total의 값인 foo(6)add(1)(6)과 같다. 따라서 total은 7이다.
  • 그렇다면 foo(3)은 무엇일까? foo(3)이 실행되면 4가 반환되지만, 이 값은 어떠한 변수에도 할당이 되지 않으므로 total에 영향을 미치지 않는다.

👉 Closure 사용의 예시

let multiplyBy = function(x) {		← 클로저 사용
  return function(y) {
    return x * y;
  }
}
  
let divideBy = function() {		
  return function(y) {
    return 10 / y;
  }
}
  • 리턴 함수가 x에 접근할 수 있기 때문에 multiplyBy가 클로저를 사용하고 있다.
  • divideBy는 내부함수에서 접근할 수 있는 외부함수의 매개변수가 없기 때문에 클로저를 사용할 수 없다.

🔖 Closure의 코딩 패턴

1. 커링

  • 함수 하나가 n개의 인자를 받는 대신, n개의 함수를 만들어 각각 인자를 받게 하는 방법
function adding(x) {		// x 값을 고정해놓고 재사용할 수 있음
  return function(y) {
    return x + y;
  }
}

adding(4)(5);			// 9

2. 클로저 모듈 패턴

  • 변수를 스코프 안쪽에 가두어 함수 밖으로 노출시키지 않는 방법
function makeCounter() {
  let privateCounter = 0;
  
  return {
    increment: function() {
      privateCounter++;
    },
    decrement: function() {
      privateCounter--;
    },
    getValue: function() {
      return privateCounter;
    }
  }
}
  • Counter에 각각 다른 privateCounter를 다루면서, privateCounter를 밖으로 노출시키지 않는다.

참고한 글
https://poiemaweb.com/js-scope
https://gmlwjd9405.github.io/2019/04/22/javascript-hoisting.html

profile
get, set, go!

0개의 댓글