상세 컨텐츠

본문 제목

[Codecademy] Learn JavaScript 4. Scope

21-22/21-22 리액트 스타터 -2

by dev otcroz 2021. 10. 8. 21:01

본문

728x90

4. Scope

● Scope

1. Scope 식별자의 유효범위

스코프는 식별자 접근 규칙에 따른 유효 범위를 의미하며 변수가 어디서 접근하고 참조할 수 있는 지를 정의한다.

전체 코드 어디에서나 접근이 가능한 변수(전역 스코프 변수)가 있다면, 특정한 곳에서 접근이 가능한 변수(지역 스코프 변수)도 있다.


2.  Blocks and Scope 블럭과 스코프

블럭은 중괄호({ })를 사용하여 코드들을 묶어주는 역할을 하며, 하나 또는 여러 줄의 코드들을 그룹화한다.

블럭은 주로 함수와 for문, if 문에서 사용된다.

const logSkyColor = () => {
  let color = 'blue'; 
  console.log(color); // blue 
}

console(logSkyColor);  // Output: blue

logSkyColor 함수는 중괄호를 사용하여 코드들을 묶어주는 역할(블럭화)을 한다.

6행에서 console(logSkyColor);로 함수를 호출하면 함수 내에 있는 내용들을 반환한다.

 

Instruction

1. 블럭과 식별자의 유효범위

stars 변수에 집중하여 코드 확인

const satellite = 'The Moon';
const galaxy = 'The Milky Way';
let stars = 'North Star';

const callMyNightSky = () => {
  stars = 'Sirius';
	return 'Night Sky: ' + satellite + ', ' + stars + ', ' + galaxy;
};

console.log(callMyNightSky()); // Output: Night Sky: The Moon, Sirius, The Milky Way
console.log(stars); // Output: Sirius
  1. 1~3행: 변수가 callMyNightSky() 함수 밖에서 선언되었으며, 변수에 각각 값을 할당하였다.
  2. callMyNightSky() 함수 : 함수 내에서 stars의 값을 재할당하였다. 
  3. console.log(callMyNightSky()) : 함수 내에 있는 내용들을 출력한다. 
  4. console.log(stars) : 함수 내에서 재할당했던 Sirius를 출력한다.

stars는 callMyNightSky() 함수 밖에서 선언된 변수이다.

함수 내에서 재할당한 'Sirius'가 stars 변수에 저장되었고 함수의 수행이 종료되어도 stars는 'Sirius'값을 유지하고 있다.

즉, stars는 함수 밖에 있는 전역 변수이기에 함수 내에서 stars에 접근할 수 있던 것이다.

+전역변수에 대한 내용은 바로 아래를 참고

 


3. Global Scope 전역 스코프

전역 스코프는 유효범위가 전역적이라는 의미이다.

즉, 전역 스코프인 변수는 함수나 반복문 등의 블럭 밖에서 선언되며 어느 곳에서나 값에 접근하고 참조할 수 있다. 

전역 스코프인 변수를 전역 변수라고 부른다. 

const food = 'hotdog';
 
const returnFood = () => {
  return food; // return: hotdog 
};
 
console.log(returnFood()); // Output: hotdog
  1. 1행 : const로 변수 food를 선언하고 문자열 'hotdog'를 할당한다.
  2. returnFood 함수 : 함수는 문자열 hotdog를 반환하는 일을 수행한다.
  3. console.log(returnFood()) : returnFood() 함수를 호출하면 returnFood()는 hotdog를 반환한다. 

함수 내에는 food가 선언되어있지 않지만, food는 전역변수로 선언되어 있어 어디서든 food 변수에 접근할 수 있다.

즉, return food;를 통해 함수는 문자열 hotdog를 반환하는 일을 수행한다.

 

Instruction

1. 전역 스코프인 변수(=전역변수)

city와 skyscraper 변수에 집중하여 코드 확인

const city = 'New York City';
const logCitySkyline = () =>{
  let skyscraper = 'Empire State Building';

  return 'The stars over the ' + skyscraper + ' in ' + city;
};

console.log(logCitySkyline());  
// Output: The stars over the Empire State Building in New York City

console.log(city); // Output: city
console.log(skyscraper);  // ReferenceError 발생
  1. 1행: 함수 밖에서 const로 city를 선언하고 동시에 값을 할당하였다.
  2. logCitySkyline() 함수: 함수 내에 변수 skyscrapher을 선언하고 값을 할당하였다. 그리고 반환값으로 함수 밖에 선언한 변수 city를 포함하였다.
  3. console.log(logCitySkyline()) : 함수 내에서 return하려는 값의 출력이 잘 이루어진다.
  4.  console.log(city)는 city를 출력, console.log(skyscraper)은 에러(ReferenceError)가 발생한다.

* ReferenceError: 잘못된 값을 참조하려고 할 때 발생하는 에러

 

city는 함수 밖에서 선언된 전역 변수, skyscraper는 함수 안에서 선언된 지역 변수이다.

city는 전역적으로 선언되었기 때문에 함수 어디에서나 사용이 가능하다. 하지만 skyscraper는 함수 내에서 선언된 변수이기에 함수 내에서만 사용이 가능하다.

즉, 마지막 행에서 console.log(skyscraper)를 실행하는 시점에 skyscraper 변수가 존재하지 않기 때문에 오류가 발생한다.

 


4. Block Scope 블럭 스코프

블럭 스코프는 유효 범위가 블럭 내라는 의미로, 지역 스코프의 한 종류이다. 즉, 블럭 스코프 변수는 지역변수라고 보면 된다.

블럭 스코프 변수는 블럭 안에서 선언된 변수로 블럭 안에서만 사용할 수 있으며, 블럭 밖에서 변수를 사용하면 에러가 발생한다. 

값에 접근하거나 참조하는 행위는 블럭 내에서만 수행할 수 있다.

 

+ 지역 스코프 변수의 종류

 - 블럭 스코프 변수: 변수를 선언할 때 let, const 예약어를 사용하여 선언

 - 함수 스코프 변수: 변수를 선언할 때 var 예약어를 사용하여 선언

const returnFood = () => {
  const food = 'hotdog';
  return food; // return: hotdog 
};
 
console.log(returnFood()); // Output: hotdog
console.log(food);  // ReferenceError
  1. returnFood 함수: 함수 내에서 const로 변수 food를 선언하고 값을 할당, 그리고 return 문으로 변수 값을 반환한다.
  2. console.log(returnFood()) : returnFood 함수를 호출하여 함수의 내용을 수행한다. 문자열 hotdog를 반환한다.
  3. console.log(food) : food는 returnFood 함수 내에서 선언된 변수이다. 이 코드를 수행할 때, 변수 food는 존재하지 않기 때문에 ReferenceError를 출력한다.

 

Instruction

1. 블록 스코프로 선언된 변수(=지역 변수)

lightWaves 변수에 집중하여 코드 확인

const logVisibleLightWaves = () =>{
  const lightWaves ='Moonlight';
  console.log(lightWaves)
};

logVisibleLightWaves()  // Output: Moonlight
console.log(lightWaves)  // ReferenceError
  1. logVisibleLightWaves 함수 : 함수 내에서 변수 lightWaves를 선언하고 console.log(lightWaves)의 내용이 담겨있다.
  2. logVisibleLightWaves(): logVisibleLightWaves() 함수를 호출하여 함수에 기술된 내용들을 출력한다.                                      즉, Moonlight를 출력한다.
  3. console.log(lightWaves) : lightWaves는 함수 내에서 선언된 블럭 스코프 변수(=지역변수)이기 때문에 변수 이름으로 값에 접근하려 할 때 ReferenceError 오류가 발생한다

5. Scope Pollution 스코프 오염

스코프 오염은 많은 전역 변수를 사용할 때 발생하는 현상

스코프 오염이 발생하는 원인

  • 전역 네임 스페이스에 많은 전역 변수가 저장
  • 다른 스코프에 있는 변수를 재사용하려고 할 때

프로그램에서 전역변수를 만들면 전역변수는 전역 네임스페이스에 저장된다. 전역 네임스페이스는 변수들이 프로그램에 어디에서나 사용할 수 있도록 한다. 전역 변수들은 프로그램이 시작하고 종료될 때까지 유지되는데, 전역변수를 많이 사용할수록 네임스페이스가 빠르게 찬다.

전역 변수를 많이 선언하게 되면 변수들을 추적하기 어려워서 충돌이 일어나는 등 문제가 발생할 수 있다. 

 

*네임 스페이스: 구분이 가능하도록 정해놓은 공간, 즉 이름 공간을 선언하여 다른 공간과 구분할 수 있다.

 

let num = 50;
 
const logNum = () => {
  num = 100; 
  console.log(num);
};
 
logNum(); // Output: 100
console.log(num); // Output: 100

변수 num을 집중하여 코드 확인하기

  1. 1행: num을 전역 스코프 변수로 선언하였다.
  2. logNum 함수: 함수 내에서 num = 100으로 값을 재할당하였다.
  3. logNum() : 함수를 호출하여 console.log(num);을 통해 100을 출력한다.
  4. console.log(num) : logNum 함수 내에서 num의 값을 재정의 했기 때문에 100이 출력된다.

위의 코드를 실행할 때 오류가 발생하지 않지만, 1행에서 전역 변수로 선언한 num = 50의 값이 사라졌다.

즉, 전역 변수는 어디에서나 접근이 가능하기 때문에 값이 유지되지 않고 재할당될 가능성이 높으며 이를 추적하기 힘들다. 

 

스코프 오염을 방지하기 위해?

코드 내에서 스코프 오염이 발생하지 않기 위해서는 전역 변수의 사용을 최소화하는 것이 좋다.

 

Instruction

1. 전역 변수와 스코프 오염

stars 변수에 집중하여 코드 확인

const satellite = 'The Moon';
const galaxy = 'The Milky Way';
let stars = 'North Star';

const callMyNightSky = () => {
  stars = 'Sirius';
  return 'Night Sky: ' + satellite + ', ' + stars + ', ' + galaxy;
};

console.log(callMyNightSky()); // Output: Night Sky: The Moon , The Milky Way, Sirius
console.log(stars); // Output: Sirius
  1. 1~3행 : 전역변수를 각각 선언한다.
  2. callMyNightSky 함수 : 함수 내에서 변수 stars 값을 재정의하고 return에 변수 stars가 포함되어 있다.
  3. console.log(callMyNightSky()) : 함수의 return 값을 출력하며, 이때 stars의 값은 Sirius이다.
  4. console.log(stars) : Sirius를 출력한다.

코드를 실행할 때 오류가 발생하지 않는다. 하지만 함수 내에서 전역 변수 stars의 값을 바꾸어서 전역변수로 선언한 stars의 원래 값이 사라지고 'Sirius' 값이 재할당되었다. 

 


6. Practice Good Scoping 좋은 스코프를 지정하는 연습

가능한 블록 스코프 변수를 사용하여 변수의 범위를 엄격하게 지정하도록 한다.

 

변수 범위를 엄격하게 지정할 때 장점

  • 코드를 더 읽기 쉽게 만든다.
  • 변수들이 프로그램의 어느 부분에서 사용되고 있는지 명확하게 파악할 수 있다.
  • 코드를 유지보수하기 좋다.
  • 각 블록(함수, 조건문, 반복문)의 사용이 끝나면 메모리 공간에서 블록이 사라짐으로써 메모리를 절약할 수 있다.

 

const logSkyColor = () => {
  const dusk = true;
  let color = 'blue'; 
  if (dusk) {
    let color = 'pink';
    console.log(color); // Output: pink
  }
  console.log(color); // Output: blue 
};
 
console.log(color); // ReferenceError

변수 color을 집중하여 코드 확인하기

  1. logSkyColor 함수: 함수 내의 중괄호로 묶인 코드들을 실행한다.
  2. if 문 밖에서 color = 'blue'를 선언하고, if 문 안에서 color = 'pink'를 선언한다. 이때, color는 블록 스코프 변수이기 때문에    각각 let으로 선언해도 오류가 발생하지 않는다.
  3. if문: console.log(color)을 출력하면 pink를 출력한다.
  4. logSkyColor 함수: console.log(color)을 출력하면 blue를 출력한다.
  5. 함수 밖의 console.log(color): 함수 밖에는 변수 color가 선언되지 않았기에 ReferenceError가 발생한다.

위의 예시에서는 블록 스코프 변수이지만 color를 재정의하여 사용하였다. 코드 작성을 통해 메모리 공간을 더 효율적으로 사용하는 방법은 각각의 변수 이름을 다르게 선언하는 것이다.

 

Instruction

1. 좋은 스코프를 지정하기 위한 연습: 각각 다른 이름의 변수 사용하기

const HavingFood = () => {
    let color = 'yellow';
    let food = 'banana';
  if (color === 'yellow'){  //if - 1
    let fruit = 'lemon';
    if (fruit === 'lemon'){  //if - 2
      console.log(fruit); // Output: lemon
    }
  }
  console.log(food); // Output: banana
};

HavingFood(); // Output lemon banana
  1. 마지막 행의 HavingFood() : 함수 내의 중괄호로 묶인 코드들을 실행한다.
  2. if문 밖에서 변수 color, food를 선언하고 if - 1문 내에서 변수 fruit를 선언한다.
  3. if - 1문에서 color == 'yellow'의 조건을 만족한다. 
  4. if - 2문에서 fruit == 'lemon' 조건을 만족하므로 console.log(fruit)에서 lemon을 출력한다.                                                          이때, if - 2 문은 if - 1문에 포함되어 있기에 if - 2문에서 lemon을 출력해도 오류가 발생하지 않는다. 
  5. console.log(food) : food가 갖고 있는 값인 banana를 출력한다.

각각 다른 이름의 변수를 사용하여 선언하였기 때문에 네임스페이스 오염이 발생할 일이 없다.

또한 블록 스코프 변수로 선언되어 스코프 오염이 발생하지 않는다.

 


Corner React Starter #2

Editor 숨숨

728x90

관련글 더보기