javascript/DeepDive

[Js 딥다이브] 14. 전역변수의 문제점

hw.kr 2022. 11. 10. 00:22
변수는 유효범위(스코프)생명주기를 가진다.

 

📌 변수의 생명주기

 

변수는 선언에 의해서 생성되고 할당에 의해서 값을 가진다.

식별자(변수) 는 값이 저장된 메모리 주소를 식별한다.

 

만약 변수에 생명주기가 없다면 프로그램이 종료되기 까지 계속 메모리 공간을 사용하게 되고 이 변수가 사용되지 않는다면 메모리 공간을 낭비하게 된다.

변수는 자신이 선언된 위치(스코프)에서 생성되고 자신이 선언된 위치에서 소멸된다.

 

1️⃣ 지역변수

 

var sentence = "this is global variable";

function foo(){
	var x = 10;
	console.log(sentence); // ?
    	var sentence = "this is global variable";
    
   	return x;
}

foo();
console.log(x) // ReferenceError

 

1. 변수 x 
함수 내부에서 선언된 지역변수는 함수가 값을 반환하고 종료되면 함수와 함께 소멸된다
지역변수 x 는 함수가 호출되면 엔진에 의해서 undefined 로 먼저 초기화 된다 (함수가 호출 되어야 선언됨을 기억하자!)
그리고 변수 할당문을 만나면 값이 할당 된다
함수가 return 문을 통해서 x 를 반환해줌과 동시에 x 는 소멸되고 메모리상에서 사라진다
즉, 지역변수는 함수가 호출되어 실행되는 동안에만 유효하다

 

📌 호이스팅은 스코프 단위로 동작한다

변수 선언이 스코프의 가장 선두로 끌어올려진 것처럼 동작하는 것을 말함!

 

전역변수 : 전역 스코프의 가장 선두로 끌어올려짐

지역변수 : 지역 스코프의 가장 선두로 끌어올려짐

 

2. console.log(sentence)
foo 가 호출되면 foo 함수 생성에 의해 만들어지는 지역스코프의 가장 선두로 sentence 의 선언이 올라가고 undefined 로 초기화 된다
그리고, 변수를 출력하려고 할때 렉시컬 환경을 참조해서 스코프 체인을 사용해 변수를 검색한다
우선 자기 자신의 스코프 부터 검색하고 변수 sentence 가 자신의 스코프에 있기 때문에 foo 함수 내부의 지역변수 sentence 를 참조할 수 있고 값이 할당되기 전 단계 이기 때문에 undefined 를 출력한다.

 

 

2️⃣ 전역변수

 

var x = 'global';

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

foo();
console.log(x);

 

함수나 객체 밖에서 선언한 전역변수는 호출이나 참조 없이 바로 해석되고 실행된다

foo 함수 내부에서 return 문을 통해 지역변수 x 를 반환하고 메모리상에서 소멸 됐지만,

전역변수로 사용한 x 는 함수의 생명주기와 상관없이 프로그램이 끝날때까지 메모리상에서 공간을 차지하게 된다

 

브라우저 환경에서 전역객체는 window 객체이고, 전역변수는 window 객체의 프로퍼티가 된다.

전역변수의 생명주기는 전역객체의 생명주기와 일치한다!

 

🧐 전역변수의 문제점

 

  • 전역변수로 선언한 변수는 위치 상관없이 모든 코드에서 참조가 가능하다

이말은, 모든 코드가 전역변수의 값이나 상태를 변경할 수 있다는 것을 의미하고 의도치 않게 상태가 변경될수도 있다는 것이다

변수의 유효범위는 좁을수록 좋다

  • 긴 생명주기

전역변수의 생명주기는 전역객체의 생명주기와 같고 이는 프로그램이 끝날때 까지 메모리 상에서 공간을 차지한다는 것이다

긴 생명주기는 전역변수의 변경될수 있는 가능성을 높인다, 전역변수의 상태가 변경될 수 있는 기회가 많다는 것!

  • 스코프 체인의 종점

스코프 체인 상에서 가장 상위에 위치하기 때문에 검색 속도가 가장 느리다

  • 네임스페이스 문제

자바스크립트는 파일이 분리되어 있어도, 전역스코프는 하나이다.

다른 파일에서 같은 이름의 변수를 사용하면 변수의 재할당이 발생한다.

 

 

📌 클로저 활용해서 전역변수 사용 줄이기

 

클로저 사용시 장점

  1. 지역변수의 사용을 줄임
  2. 캡슐화 

 

아래의 2가지 경우를 비교해보자

function outer(){
	var myName = "woong";
    	console.log(myName);
}
  
outer(); // woong
console.log(myName) // referenceError

 

function outer(){
    var myName = "woong";
    console.log(myName);

    return {
        inner(){
            var greeting = "hello"
            console.log(`${greeting} ! ${myName}`);
        }
    }
}

var foo = outer(); // woong
foo.inner(); // hello ! woong
console.log(foo.myName()); // undefined;

 

outer 함수는 객체를 반환해주고 그 객체에는 inner 메서드가 있다.

inner 메서드를 정의할 때 inner 메서드의 상위스코프인 outer 함수의 지역변수 myName 을 사용했다

outer 함수를 실행하면 객체를 반환해주고 그 객체에는 inner 메서드가 있다

 

지역변수의 생명주기를 생각해보면 outer 함수가 호출되고 종료되었기 때문에 myName 지역변수가 메모리상에서 사라졌을 것이다.

하지만, inner 메서드를 실행하면 myName 이 정상적으로 출력된다.

 

🧐 Why?

클로저는 함수가 정의 되는 시점의 렉시컬 환경을 기억한다

inner 함수가 정의된 시점에 지역변수 myName 을 참조했기 때문에 그 환경을 기억한다

따라서 함수 밖에서 outer 함수가 반환해준 inner 함수를 호출할 때마다 언제든지 myName 변수에 접근할수 있게 되고, 전역변수 처럼 사용할 수 있다.

하지만 이 myName 에 직접 접근할수 없어 상태를 변경할 수 없기 때문에 안전하다는 장점이 있다.

 

 

지금은 렉시컬 환경, 실행 컨텍스트에 대한 이해가 완벽하지 않아서 글을 적는 와중에도 잘 모르겠다,,

2개를 공부하고 나서 다시 클로져 정리를 해야겠다

'javascript > DeepDive' 카테고리의 다른 글

💡 클로져  (0) 2023.02.01
[Js 딥다이브] 15. let, const  (0) 2022.11.14
[Js 딥다이브] 13. 스코프  (0) 2022.11.07
[Js 딥다이브] 12. 함수 (2)  (0) 2022.11.06
[Js 딥다이브] 12. 함수 (1)  (1) 2022.11.05