스코프와 클로져

Southbig·2021년 5월 30일
0
post-thumbnail

스코프

변수에 접근 할 수 있는 범위

확인
안쪽 변수가 선언되었는가, 바깥쪽 변수가 선언 되었는가.
바깥쪽 스코프에서 선안한 변수는 안쪽 스코프에서 사용가능.
안쪽 스코프에서 선언한 변수는 바깥쪽에서는 사용이 안됨.

  1. 안쪽 스코프에서 바깥쪽 스코프로는 접근 할 수 있지만, 반대는 불가능
  2. 스코프는 중첩이 가능

3.가장 바깥쪽은 전역(global scope) 그 외에는 (local scope) 라고 부름.
4. 지역(local scope)는 전역(globa scope) 보다 더 놓은 우선순위를 가짐.

스코프의 종류

1. 블록스코프(black scope)

중괄호로 둘러 싸인 범위 -> 반복문의 변수 i는 중괄호 안에서만 사용가능.

2. 함수스코프(function scope)

함수로 둘러 싸인 범위 -> 화살표 함수는 블록스코프로 취급.

var, let, const 키워드 특징과 차이

var 키워드는 블록스코프를 무시하고, 함수 스코프만 따른다.
vat 키워드는 재선언을 해도 에러가 안난다.

let 키워드는 재선언을 하면 연습모드에서는 가능하지만 사실파일을 불러 올때 불가능.
let 키워드는 블록스코프를 따름.

const 키워드는 값이 변하지 않는 상수(constant)를 정의 할때 사용 -> 값 재할당 불가능.

'use strict'; // 선없는 변수는 에러로 걸러줌.

  • 추가
    브라우저에는 window라는 객체가 존재, 브라우저 창을 대표하는 객체이며, 브라우저 창과 관계없이 전역 항목도 담고 있다.

클로저

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

  • 함수와 함수가 선언된 => 함수를 리턴하는 함수
  • 어휘적환경 => 변수 및 함수 선언의 형태

클로저는 리턴하는 함수에 의해 스코프(변수에 접근 범위)가 구분 된다

클로저 핵심
스코프를 이용해, 변수의 접근 범위를 닫는데에 있다

클로저의 특징

  1. 클로저 함수는 "함수를 리턴하는 함수" -> 함수를 리턴하는 함수가 클로저의 형태를 만든다.(함수와 함수가 선언된 어휘적 환경의 조합)
  2. 클로저 함수는 "내부 함수는 외부 함수에 선언된 변수에 접근 가능하다"

클로저의 활용

일반적인 함수는, 함수 실행이 끝나고 나면 함수 내부의 변수를 사용할 수 없다
하지만 클로저는 외부함수의 실행이 끝나도, 외부함수 내 변수가 메모리 상에 저장된다(어휘적 환경을 메모리에 저장하기 때문에 가능하다)

ex)

const adder = function (x) {
  return function(y) {
    return x + y
  }
}
const add5 = adder(5);

위의 코드와 같이 함수 실행이 끝나도 5라는 값은 x에 담겨져서 사용이 가능하다

// add5는 다음과 같이 사용할 수 있다
add5(7) // 12
add5(10) // 15

ex)

const tagMaker = tag => content => `<${tag}>${content}</${tag}>`
//div 태그 생성
const divMaker = tagMaker('div');
divMaker('hello')
divMaker('world')
//a 태그 생성
const anchorMaker = tagMaker('a');
anchorMaker('go')
anchorMaker('back')

위의 예제와 같이 클로저특정 데이터를 스코프안에 가두어 둔 채로 계속 사용할 수 있게 해준다

클로저 모듈 패턴

클로저를 이용해 내부 함수를 단 하나만 리턴하는 것에 그치지 않고, 객체에 담아 여러 개의 내부 함수를 리턴하도록 만들 수 있다.

ex)

const makeCounter = () => {
  let value = 0;
  //return에 객체를 만들어 여러 함수를 값으로 만든다
  return {
    increase: () => {
    value = value + 1
    },
    decrease: () => {
    value = value - 1
    },
    getValue: () => value
  }
}
const counter1 = makeCounter();
const counter1 = makeCounter();
counter1 // { increase: f, decrease: f, getValue: f}

makeCounter 함수는 increase, decrease, getValue메소드를 포함한 객체 하나를 리턴한다 따라서, counter1은 객체

중요
외부 스코프에서는 내부 스코프의 변수에 접근할 수 없다 는 규칙에 의해
makeCouter 함수를 바꾸지 않고 value 변수의 값을 새롭게 할당할 수 있는 방법은 없다
하지만, 리턴하는 객체가 제공하는 메소드를 통해 value값을 간접적으로 조작할 수 있다
이것이 바로 정보의 접근 제한(캡슐화) 이다

정보의 접근 제한(캡슐화)를 해야만 하는이유

만약 스코프로 value값을 감싸지 않았다면, value값은 전역 변수여야만 할 것이다

전역 변수는 다른 함수 혹은 로직등에 의해 의도되지 않을 변경을 초래(side effect) 하기 때문에 캡슐화로 오류로부터 안전하게 값을 보호 할 수 있다

즉, side effect를 최소하하면, 의도되지 않은 변경을 줄일 수 있고, 값을 보호 할 수 있다

클로저를 통해 불필요한 전역 변수 사용을 줄이고, 스코프를 이용해 값을 보다 안전하게 다룰 수 있다

const counter1 = makeCounter();
counter1.increase()
counter1.increase()
counter1.decrease()
counter1.getValue() // 1
//
const counter2 = makeCounter();
counter2.decrease()
counter2.decrease()
counter2.decrease()
counter2.getValue() // -3

위의 예제와 같이 makeCounter에 의해 리턴된 객체는 makeCounter를 실행할 때에 선언되는 value값을 각자 독립적으로 가지데 된다

counter1에서의 value와 counter2에서의 value는 서로에게 영향을 끼치지 않고, 각각의 값을 보존할 수 있다

함수 재사용성을 극대화하여, 함수 하나를 완전히 독립적인 부품 형태로 분리하는 것을 모듈화라고 한다

클로저를 통해 데이터와 메소드를 같이 묶어서 다를 수 있다, 클로저는 모듈화에 유리하다

github 스코프 클로저 MDN 정리

profile
즐겁게 살자

0개의 댓글