JavaScript - 스코프(유효범위)에 대해 알아보자

Sonny·2019년 9월 18일
5

JavaScript

목록 보기
10/29
post-thumbnail

스코프 (유효범위)

Scope의 정의 📋

  • 자신이 선언된 위치에 의해 다른 코드가 식별자 자신을 참조할 수 있는 유효범위
  • 자바스크립트 엔진이 식별자를 검색할 때 사용하는 규칙

Scope의 구분 ⚖️

  • 전역 스코프 (Global scope)

    전역: 코드의 가장 바깥 영역

    • 어디에서든지 참조 가능
  • 지역 스코프 (Local scope / Function-level scope)

    지역: 함수 몸체 내부

    • 자신이 선언된 지역과 하위 함수에서만 참조 가능
    • 자신의 지역 스코프와 하위 스코프에서 유효
    • 함수에 의해서만 지역 스코프가 생김

Scope의 동작 과정 💪

var a = 1;

function foo () {
  var b = 2;		
  
  console.log(a);
  console.log(b);
}

foo();
console.log(b);		// 'b'에 접근할 수 없다.
  • 함수 내부에 없는 변수 a를 불러오는 경우
    • 식별자 결정 과정을 통해 함수 내부에서 먼저 a라는 변수를 찾음
    • 함수 내부에 변수 a가 없어 외부에서 변수 a를 찾아 불러옴
  • 변수 b는 본인이 속한 함수내에서만 접근가능하도록 범위가 정해짐.

식별자 결정: 어떠한 변수를 참조할 것인지 결정하는 과정

Scope의 규칙 🔏

Scope는 함수를 호출할 때가 아니라 선언할 때 생긴다.

1. 함수 내부에서 변수를 참조할 경우

  • 함수 내부에서 변수를 먼저 찾음
  • 함수 내부에 X → 함수 외부에서 찾음

2. 함수 내부, 외부에 동일한 변수명이 존재할 경우

  • 함수에서는 내부의 변수를 우선시 함

3. 함수 내부, 외부에서의 규칙

  • var의 경우, 내부/ 외부를 판별하는 기준은 함수
  • 함수 내부에서 선언된 변수? 함수 외부에서 참조 불가
  • 함수 외부에서 선언된 변수? 함수 내부에서 참조 가능

Scope의 특징 🙌

  • var 키워드로 선언된 변수는 함수 레벨 스코프를 따름

    함수 레벨 스코프 (Function-level scope)

    • 함수 내에서 선언된 지역 변수는 함수 내에서만 유효
    • 함수 외부에서는 참조 불가
  • let,const 키워드로 선언된 변수는 블록 레벨 스코프를 따름

    블록 레벨 스코프 (Block-level scope)

    • 코드 블록 내에서 선언된 변수는 코드 블록 내에서만 유효, 코드 블록 외부에서는 참조 불가
    • 코드 블록 내부에서 선언한 변수는 지역 변수

Scope의 종류 📚

전역 스코프 (Global Scope)

  • 전역에 변수를 선언하면 이 변수는 어디서든지 참조할 수 있는 전역 스코프를 갖는 전역 변수가 됨
  • var키워드로 선언한 전역 변수는 전역 객체(Global Object)
  • 전역 스코프의 문제점
    • 변수 이름 중복의 위험성
    • 의도치 않은 재할당에 의한 상태 변화로 코드를 예측하기 어려움

비 블록 레벨 스코프(Non block-level scope)

if (true) {
  var x = 5;
}
console.log(x);	// 5;
  • 변수 x는 코드 블록 내에서 선언
  • 자바스크립트는 블록 레벨 스코프를 사용하지 않음
  • 코드 블록 내에서 선언되었지만 함수 밖에서 선언된 변수는 모두 전역스코프를 갖게됨
    → 변수 x는 전역 변수

함수 레벨 스코프 (Function-level scope)

var x = 1;

if (true) {
  // x는 전역 변수, 이미 선언된 전역 변수 x가 있어 x 변수는 중복 선언
  var x = 10;
}

console.log(x); // 10
  • var 키워드로 선언한 변수는 함수의 코드 블록만을 지역 스코프로 인정
  • 함수 외부에서 var키워드로 선언한 변수는 코드 블록 내에서 선언해도 모두 전역변수가 됨
var i = 10;

// var 키워드로 for 문에서 선언한 변수 i는 전역변수
// 이미 선언한 전역 변수 i가 있으므로 중복 선언
for(var i = 0; i < 5; i++) {
  console.log(i) // 0 1 2 3 4 5
}

// 의도치 않게 변수와 값이 변경
console.log(i) // 5
  • for문의 변수 선언문에서 var키워드로 선언한 변수도 전역 변수가 됨

예시로 알아보는 함수 레벨 스코프 1

var x = 'global';

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

foo();            // local
console.log(x);   // global
  • 전역변수 x와 지역변수 x가 중복 선언
  • 전역 영역에서는 전역변수만이 참조 가능
  • 함수 내 지역 영역에서는 전역, 지역 변수 모두 참조 가능
  • 변수명이 중복된 경우, 지역변수를 우선하여 참조

예시로 알아보는 함수 레벨 스코프 2

var x = 'global';

function foo() {
  var x = 'local';
  console.log(x);          // local
    
  function bar() {	   // 내부함수
    console.log(x);	   // local
  }
    
  bar();
}

foo();
console.log(x);	// global
  • 내부함수는 자신을 포함하고 있는 외부함수의 변수에 접근 가능
  • 함수 bar에서 참조하는 변수 x는 함수 foo에서 선언된 지역변수
    → 실행 컨텍스트의 스코프 체인에 의해 참조 순위에서 전역변수x가 뒤로 밀림

스코프 체인: 스코프가 계층적으로 연결된 것

예시로 알아보는 함수 레벨 스코프 3

var x = 10;

function foo() {
  x = 100;
  console.log(x);   // 100
}

foo();
console.log(x);     // 100
  • 함수(지역) 영역에서 전역변수 참조가능
    전역변수의 값 변경가능
  • 내부 함수의 경우, 전역변수는 물론 상위 함수에서 선언한 변수에 접근/변경이 가능

예시로 알아보는 함수 레벨 스코프 4

var x = 10;

function foo() {
  var x = 100;
  console.log(x);	// 100
    
  function bar() {
    x = 1000;
    console.log(x);	// 1000
  }
    
  bar();
}

foo();
console.log(x);	// 10
  • 중첩 스코프는 가장 인접한 지역을 우선하여 참조

예시로 알아보는 함수 레벨 스코프 5

var foo = function () {
  var a = 3;
  var b = 5;
  
  console.log(a, b);            // a:3, b:5
  var bar = function (){
    var b = 7;
    var c = 11;
    
    console.log(a, b, c);       //  a:3, b:7, c:11
    a += b + c;
    console.log(a, b, c);       // a:21, b:7, c:11
  };
    
  bar();
};

foo();

렉시컬 스코프

함수를 어디에 선언하였는지에 따라 결정되는 환경

  • 함수를 어디서 정의했는지에 따라 상위 스코프를 결정
  • 함수가 호출된 위치는 스코프 결정에 아무런 의미를 주지 않음
    → 함수의 상위 스코프는 자신이 정의된 스코프
  • 함수 정의가 실행되어 생성된 함수 객체는 함수 호출때마다 함수의 상위 스코프를 참조할 필요가 있어 결정된 상위 스코프를 기억
var x = 1;

function foo() {
  var x = 10;
  bar();
}

function bar() {
  console.log(x);
}

foo(); // 1
bar(); // 1
  • 함수 bar는 전역에 선언
    → 함수 bar의 상위 스코프는 전역 스코프
    → 전역 변수 x의 값 1을 두번 출력

함수를 어디서 호출하였는지에 따라 bar의 상위 스코프를 결정하는 경우 (동적 스코프)

  • bar의 상위 스코프: 함수 foo와 전역

함수가 어디에서 정의 되었는지에 따라 bar의 상위 스코프를 결정하는 경우(렉시컬 스코프 || 정적 스코프)

  • bar의 스코프: 전역

암묵적 전역 변수 🤫

function foo() {
  x = 10;
}

foo();
console.log(x);	// 10
  • 함수 foo내에 선언되지 않은 변수 x에 값 10을 할당

  • 변수 x의 참조를 찾아야 변수 x에 값을 할당할 수 있음
    → 자바스크립트 엔진이 스코프 체인에서 변수 x를 검색하기 시작

  • foo 함수의 스코프에서 변수 x를 검색

    • foo 함수의 스코프에는 변수 x에 대한 변수 선언이 없으므로 검색에 실패
    • foo 함수의 상위 컨텍스트(위 예제의 경우 전역 스코프)에서 변수 x를 검색
  • 전역 스코프에도 변수 x가 존재하지 않기 때문에 ReferenceError를 발생시킬 것 같지만 __전역 변수x를 암묵적으로 생성하고 값을 할당

  • var 키워드를 생략한 변수는 암묵적으로 전역 변수
    → 이러한 변수를 암묵적 전역 변수(implicit global)라 함

개발자의 의도와는 상관없이 동작하는 암묵적 전역 변수는 오류의 발생 원인이 될 가능성이 크기 때문에 변수를 선언할 때는 반드시 let 키워드를 사용

변수 이름의 중복 🛠

// x.js
function foo() {
  // var i = 0;
  i = 0;
  // ...
}

// y.js
for (var i = 0; i < 5; i++) {
  foo();
  console.log(i);
}
  • x.jsy.js에 모두 의도하지 않은 변수 i가 존재

  • HTML에서 이 2개의 자바스크립트 파일을 로드하면 변수 i는 중복됨

  • x.js의 변수 ivar키워드를 사용하지 않았으므로 암묵적으로 전역 변수화

  • y.js의 변수 i는 전역변수

  • 자바스크립트는 변수명의 중복을 허용
    → 어떠한 에러 메시지도 발생시키지 않음
    무한 반복상태에 빠지게 됨.

전역변수의 무분별한 사용은 위험하다. 전역변수를 반드시 사용하여야 할 이유를 찾지 못한다면 지역변수를 사용하여야 하며 변수의 범위인 스코프는 좁을수록 좋다.

최소한의 전역변수 사용하는 방법 📚

1. 전역변수 객체를 만들어서 사용하기

var MYAPP = {};

MYAPP.student = {
  name: 'Lee',
  gender: 'male'
};

console.log(MYAPP.student.name);

2. 즉시실행함수를 이용하여 사용하기

(function () {
  var MYAPP = {};

  MYAPP.student = {
    name: 'Lee',
    gender: 'male'
  };

  console.log(MYAPP.student.name);
}());

console.log(MYAPP.student.name);
  • 즉시 실행 함수(IIFE, Immediately-Invoked Function Expression)를 사용하면 전역변수를 만들지 않음
  • 즉시 실행 함수는 즉시 실행되고 그 후 전역에서 바로 사라진다.

참고사이트 📄

profile
FrontEnd Developer

1개의 댓글

comment-user-thumbnail
2023년 4월 18일

Very good, I think I found the knowledge I needed. I will see and refer to some information in your post. thank you!

https://surgery-costs.com/nose-surgery-cost-in-nepal/

답글 달기