JavaScript 함수의 범위(scope)

김대은·2022년 7월 21일
0

전역 변수 와 지역 변수

전역 변수란 자바스크립트에서 제일 바깥범위(함수 안에 포함되지않은)에 변수를 만드는겁니다.
window객체에 변수를 만드는거죠.

let x ='global'
function ex(){
  let x = 'local'
  x ='change'
 }
 ex();
 console.log(x) // 'global'

위 예제를 보면 같은 변수 x 여도 ex 함수 바깥의 x 는 전역 변수 이고,
ex 함수 안의 x 는 ex 함수의 지역 변수 입니다.

스코프

위 예제에서 지역 변수는 전역 변수에 영향을 끼칠 수 없습니다.
바로 함수 스코프 때문이죠.
범위 라는 말 처럼 함수 안에서 선언된 변수는 함수 안에서만 사용 가능 합니다.

또 다른 예를 들어보겠습니다.

let x= 'global';
function ex(){
  x = 'change';
 } 
 ex();
 console.log(x); // 'change'

아까와는 달리 ex 함수 안에서 선언을 하지 않았습니다.
이번엔 x='change' 를 했을때 전역 변수가 변경되었습니다.
이는 자바스크립트는 변수의 범위를 호출한 함수의 지역 스코프 부터 전역 변수들이 있는 전역 스코프 까지 점자 범위를 넓혀가며 찾기 때문입니다.

함수 ex의 범위 안에서 x가 없기때문에 전역 변수에 있는 x를 찾아온거죠.
정확한 원리는 아래 실행 컨텍스트에서 확인 가능합니다

스코프 체인

내부 함수에서는 외부 함수에 접근이 가능하지만, 반대의 경우는 안됩니다.
그리고 모든 함수들은 전역 변수에 접근 할 수 있죠.

let name ='kim'
function outer(){
 console.log('외부',name);
  function inner(){
  let gender = 'man';
  console.log('내부',name);
  }
  inner();
  }
  outer();
  console.log(gender); // undefined

inner 함수는 name 변수를 찾기위해 자신의 스코프에서 찾고, 없으면 한 단계 올라가 outer 스코프에서 찾고, 없으면 다시 올라가 전역 스코프 에서 찾습니다.
이렇게 꼬리를 물고 계속 범위를 넓히며서 찾는 관계를 스코프 체인 이라고 합니다.

렉시컬 스코핑(lexical scoping)

스코프는 함수를 호출때가 아니라 선언할 때 생깁니다.

let name = 'kim';
function log() {
  console.log(name);
}

function wrapper() {
  name = 'nam';
  log();
}
wrapper();

위 예제에서는 콘솔이 'nam' 으로 찍힙니다만

let name = 'kim';
function log() {
  console.log(name);
}

function wrapper() {
  let name = 'nam';
  log();
}
wrapper();

이 예제는 콘솔에 'kim'이 찍히게 됩니다.

함수를 처음 선언하는 순간, 함수 내부의 변수는 자기 스코프로부터 가장 가까운 곳(상위 범위에서)에 있는 변수를 계속 참조하게 됩니다.
위의 예시에서는 log 함수 안의 name 변수는 선언 시 가장 가까운 전역변수 name을 참조하게 됩니다.
그래서 wrapper 안에서 log를 호출해도 지역변수 name='nam'를 참조하는 게 아니라 그대로 전역변수 name의 값인 kim 나오는 겁니다.
무슨 짓을 해도 log 함수가 한 번 선언된 이상, 전역변수를 가리키게 되어있는 name 변수가 다른 걸 가리키게 할 수 없습니다.
유일한 방법은 아까처럼 전역변수를 다른 값으로 바꾸는 겁니다

변수 은닉화, 네임스페이스

전역 변수를 만드는것을 지양 하는게 좋은게,
앱을 만들면서 다른사람들과 협업을 하거나, 라이브러리를 사용할때,
우연의 일치로 인해 같은 변수 이름을 사용해서 이전에 있던 변수를 덮어 쓰는 불상사가 발생할 수 있다.

이를 해결하기 위한 방법은 전역 변수 대신 함수 안에 넣어 지역 변수로 만드는것 이다.
아니면 객체 안에 속성으로 만들 수 있다.

let obj = {
  x: 'local',
  y: function() {
    alert(this.x);
  }
}

이러면 obj.x /obj.y() 이렇게 접근해야 하기때문에 다른사람과 섞일 염려가 없다.

이런 방법을 네임스페이스를 만든다 합니다.
대부분의 라이브러리가 이 방식을 사용합니다. 제이쿼리같이요

또는 IIFE(즉시 호출 함수 표현식 , 모듈 패턴) 을 사용하면 함수를 선언하자마자 바로 실행시켜버리기 때문에 변수가 변경 될 일이 없다.

profile
매일 1% 이상 씩 성장하기

0개의 댓글