스코프

유슬기·2023년 1월 3일
0

프론트엔드

목록 보기
16/64
post-thumbnail

스코프란?

변수 접근 규칙에 따른 유효 범위로, 중괄호(블록) 또는 함수에 의해 나누어진다.

  1. 안쪽에 변수가 선언되었는가, 바깥쪽에 변수가 선언되었는가에 따라 변수 접근 가능여부가 달라진다.

    • 바깥쪽 스코프에서 선언한 변수 → 안쪽 스코프에서 사용 가능
    • 안쪽 스코프에서 선언한 변수 → 바깥쪽 스코프에서 사용 불가
    let username = 'kimcoding';
    if (username) {
      let message = `Hello, ${username}!`;
      console.log(message); // Hello, kimcoding!
    }
    
    console.log(message); // message is not defined

    4번째 줄에서 message를 출력할 때는, 3번째 줄의 username을 바깥 스코프에서 가져왔으므로 정상적으로 출력된다.

    6번째 줄에서는 message라는 변수 자체가 안쪽 스코프에 선언되어 있으므로 바깥쪽에서는 접근할 수 없어 ReferenceError를 낸다.

    let greeting = 'Hello';
    function greetSomeone() {
      let firstName = 'Josh';
      return greeting + ' ' + firstName;
    }
    
    console.log(greetSomeone()); // Hello Josh
    console.log(firstName); // firstName is not defined

    greeting 변수는 바깥 스코프에 정의되어 있으므로 함수 안쪽에서 사용할 수 있다. 따라서 greeting 변수와 firstName 변수의 조합에 의해 'Hello Josh' 문자열이 출력된다.

    firstName 변수는 안쪽 스코프에 선언되어 있으므로 바깥쪽에서는 접근이 불가능해 ReferenceError를 낸다.

  2. 중첩이 가능하며, 가장 바깥의 스코프는 전역 스코프(Global scope)라고 부른다.

    • 전역이 아닌 다른 스코프는 전부 지역 스코프(local scope)

      scope

  3. 지역 변수전역 변수보다 더 높은 우선순위를 가진다.

    • 지역 변수: 지역 스코프에서 선언한 변수
    • 전역 변수: 전역 스코프에서 선언한 변수
    let name = '김코딩'; // 전역 변수
    
    function showName() {
    	let name = '박해커'; // 지역 변수
    	console.log(name); // 박해커
    }
    
    console.log(name); // 김코딩
    showName();
    console.log(name); // 김코딩

    첫 번째와 세 번째 출력은 전역 변수로 선언된 name을 가져온다.
    (showName 함수 안쪽에 선언된 지역 변수 name은 안쪽 스코프이므로 접근이 불가능함)

    두 번째 출력(showName();)은 함수 안에서 선언한 name이라는 지역 변수에 접근하고 있다.
    변수 이름이 전역 변수와 똑같지만, 지역 변수가 전역 변수보다 우선순위가 높으므로, 지역 변수 name이 출력된다.

    동일한 변수 이름으로 인해 바깥쪽 변수가 안쪽 변수에 의해 가려지는(shadow) 이러한 현상을 쉐도잉(variable shadowing)이라고 부름

    let name = '김코딩';
    
    function showName() {
    	name = '박해커'; // let 키워드를 이용해 선언하지 않았으므로, 첫 번째 줄의 전역 변수 name을 사용 → 이때, 전역 변수 name의 값이 바뀜
    	console.log(name); // 박해커
    }
    
    console.log(name); // 김코딩
    showName();
    console.log(name); // 박해커

    위의 예제와 다르게 세 번째 줄에서 let 키워드를 이용해 선언하지 않았다.
    ‘박해커’라는 값으로 할당하고 있는 name 변수는 전역에 선언된 name 변수를 그대로 사용하겠다는 의미

    지역 스코프에서 새로 선언되지 않으면 같은 변수이다.
    showName 함수가 실행되기 전, 첫 번째 출력에서는 ‘김코딩’을 출력하고, 그 이후에는 전역변수 name의 값이 바뀌기 때문에 두 번째와 세 번째 출력에 ‘박해커’가 출력된다.


스코프의 종류

스코프의 종류에는 두 가지가 있다.

  1. 블록 스코프(block scope): 중괄호를 기준으로 범위가 구분됨. (조건문이나 반복문의 중괄호도 포함)

  2. 함수 스코프(function scope): 함수로 둘러싼 범위. function 키워드가 등장하는 함수 선언식 및 함수 표현식은 함수 스코프를 만든다.

    주의: 화살표 함수는 블록 스코프로 취급됨

블록 스코프 안에서 정의된 변수는 블록 범위를 벗어나는 즉시 접근이 불가하다.

for (let i = 0; i < 5; i++) {
	console.log(i); // (다섯 번 반복)
}
console.log('final i:', i); // i is not defined

위의 예제의 세 번째 줄에서 출력하려는 변수 i는 블록 범위를 벗어났기 때문에 ReferenceError가 나옴

조건문 내의 변수 선언을 let 키워드가 아닌 var 키워드를 이용하면 어떻게 될까?

for (var i = 0; i < 5; i++) {
	console.log(i); // (다섯 번 반복)
}
console.log('final i:', i); // final i: 5

결과는 5로 잘 나온다. 왜?

여기서 var 키워드는 for 문이 만들어낸 블록 스코프를 무시하기 때문이다.

변수 선언 키워드

  1. varlet

    var 키워드로 정의한 변수는 블록 스코프를 무시하고, 함수 스코프만 따른다. (화살표 함수의 블록 스코프는 무시하지 않음)

    보통 코드를 작성할 때 블록은 들여쓰기가 적용되고, 그 구분이 시각적으로 분명하기 때문에 대다수의 사람들은 블록 스코프를 기준으로 코드를 작성한다.

    블록 단위로 스코프를 구분했을 때, 훨씬 더 예측 가능한 코드를 작성할 수 있으나, var는 이 규칙을 무시하기 때문에 비교적 예측이 어렵다.

    또한, let 키워드는 재선언을 하면 에러를 내 재선언을 방지해주나 , var 키워드는 재선언을 해도 아무런 에러가 나지 않아 재선언 방지가 되지 않는다.

    이러한 점 때문에 var 키워드보다 let 키워드의 사용이 권장된다.

  2. const

    변하지 않는 값, 상수(constant)를 정의할 때 이용한다.

    const는 값의 재할당이 불가능하다. 값을 재할당할 경우 TypeError를 내므로, 의도하지 않은 값의 변경을 막을 수 있다.
    변수 선언 키워드

변수 선언 시 주의할 점

  1. 브라우저에는 window라는 객체가 존재함

    • 브라우저 창을 대표하는 객체
    • 브라우저 창과 관계없이 전역 항목도 담고 있음
    • var로 선언된 전역 변수 및 전역 함수는 window 객체에 속하게 된다
  2. 전역 변수는 최소화 하자

    • 전역 변수: 어디서든 접근 가능한 변수
    • 편리한 대신 다른 함수 혹은 로직에 의해 의도되지 않은 변경이 발생할 수 있음 → 사이드 이펙트(side effect) 발생
  3. let, const를 주로 사용하기

    • var는 블록 스코프를 무시하며, 재선언을 해도 에러를 내지 않음
      • 같은 스코프에서 동일한 이름의 변수를 재선언 하는 것은 버그를 유발한다
    • 전역 변수를 var로 선언하는 경우 문제가 될 수 있음
      • 예를 들어, var 키워드로 console이라는 변수를 선언했을 때, window의 내장 기능인 console을 덮어버려 내장 기능을 사용할 수 없게 만듦
  4. 선언 없는 변수 할당 금지

    • 선언 없이 변수를 할당하면 해당 변수는 var로 선언한 전역 변수처럼 취급됨
    function showAge() {
    	age = 90;
    	console.log(age); // 90
    }
    showAge();
    console.log(age); // 90
    console.log(window.age); // 90
    • 실수를 방지하기 위해 Strict Mode(엄격 모드)를 사용할 수 있음
      • Strict Mode는 브라우저가 보다 엄격하게 작동하도록 만들어줌
      • 선언 없는 변수 할당의 경우도 Strict Mode는 에러로 판단
      • js 파일 최상단에 ‘use strict’ 라고 입력하면 사용 가능
profile
아무것도 모르는 코린이

0개의 댓글