whatisthis?

javaScript. (17) 함수 스코프 본문

WEB STUDY/JAVASCRIPT

javaScript. (17) 함수 스코프

thisisyjin 2022. 1. 28. 14:18

자바스크립트에서 ECMAscript 5 이전에는 var로 선언한 변수로 데이터를 저장했었다.

(ECMA5이후에는 const와 let이 등장하였다. 현재 var은 웬만해선 쓰지 X)

 

var로 전역(global)변수를 만드는 것은 삼가야 한다!

그렇다면, 전역 변수란 무엇이며, 삼가야 하는 이유는 무엇일까?

 

 


 

** 전역변수 (global variable)

자바스크립트에서 가장 바깥 범위(window 객체)에 변수를 만드는 것.

함수 안에 포함되지 않음.

 

예제를 통해 살펴보자.

var x = 'global';
function ex() {
  var x = 'local';
  x = 'change';
}
ex(); // x를 바꿔본다.
alert(x); // 여전히 'global'

함수 ex 안의 x는 local 변수(지역변수) 이고, 함수 바깥의 변수는 global 변수(전역변수)이다.

ex()로 ex함수를 호출하여 x값을 change로 바꾸었으나,

함수 바깥에서의 x는 여전히 global 이다.

 

 


 

window 객체와 BOM에 대해 아래 포스팅에서 다루도록 하겠다.

🔻🔻🔻

https://mywebproject.tistory.com/231

 

javaScript. Window 객체와 BOM

 

mywebproject.tistory.com

 

💡 Window 객체란?

- 브라우저의 요소들과 자바스크립트 엔진, 그리고 모든 변수를 담고 있는 객체

- 브라우저 전체를 담당하는 것이 Window 객체 (cf. Document 객체 = 웹사이트만 담당)

- Document 객체도 Window 객체 안에 들어있음.

 

window객체 아래에는 많은 속성(property)과 메소드(method)가 존재함.그중에서도 대표적인 것을 살펴보면

 

* 객체 : screen , location ,  history , document 객체

* 메소드 : parseInt , isNaN 등

 

 

사실 parseInt같은 경우에도 window.parseInt()라고 작성하지 않고 parseInt()라고만 작성한다.

Window 객체는 모든 객체의 조상, 즉 전역객체(global object)이다.

모든 객체를 다 포함하고 있기 때문에 window는 그냥 생략 가능.

 

window 객체 아래를 보면 자료형(String, Boolean, Number, Function, Array)이 다 들어있다.

게다가 선언한 변수들도 모두 window 객체 내에 저장된다.

( ❗ 단, 함수 내에서 선언한 변수는 아님 )

 

 

 

💡 window 객체의 대표적인 메소드들 

-> window.는 생략해도 좋으나, 다른 함수와 헷갈릴 수 있으니 붙여줘도 괜찮음. 

 

📁 window.close()

- 현재 창을 닫음. 

 

📁 window.open()

- 새 창을 염. (새탭 / 현재탭 / 팝업창 *width,height설정*)

open('https://mywebproject.tistory.com')  // 새 탭에서 열기
open('https://mywebproject.tistory.com', '_self')  // 현재 탭에서 열기
open('','','width=200,height=200')  // 가로세로 200px의 팝업창

+) document.write로 새 창의 내용을 변경할 수도 있음.

var popup = window.open('', '', 'width=200,height=200');
popup.document.write('안녕하세요');

++) 팝업창에서 원래 탭에 접근 = opener 객체 사용

 

📁 window.encodeURI() / decodeURI()

- 주소에 한글이 들어가면 %EC%9E%90%EB%B0%94%EC%8A%A4와 같이 이상한 문자열로 바뀜.

- 한글 -> 외계어 : encodeURI(한글)- 외계어 -> 한글 : decodeURI(외계어)

 

📁 window.setTimeout(함수, 밀리초)   :  지정한 초 뒤에 실행

📁 window.setInterval(함수, 밀리초)   :  지정한 초마다 반복

 

📁window.getComputedStyle(태그명)

- 태그에 현재 적용된 CSS 속성값을 알 수 있음. 

console.log(getComputedStyle(document.getElementById('app-root')));

이런식으로 document객체로 getElementBy__ 하거나 querySelector 하면 된다.

 


 

 

 


 

전역 변수가 무엇인지 살펴보면 다음과 같다.

var hello = 'hello?';

window.hello;         // 'hello?'

** 주의 > 위 예제는 var만 가능하다. / 즉, let이나 const는 window객체에 저장되는 전역변수가 

 

전역변수는 어디에서나 쓸 수 있고,

그에 반대되는 개념인 지역변수는 그 함수 안에서만 쓸 수 있다.

 

 

❗ 지역변수는 아무리 해도 전역변수에 영향을 끼칠 수 없다.  -> 함수 스코프(scope) 때문.

- 함수 안에서 선언된 변수는 해당 함수 안에서만 사용 가능하다.

 

 

예외를 살펴보면 다음과 같다.

var x = 'global';
function ex() {
  x = 'change';
}
ex();
alert(x); // 'change'

첫번째 예제는 함수 내에서 var을 선언하였지만,

ex 함수 내에서 var을 선언하지 않은 경우에는 전역변수(global variable)의 값을 바꿀 수 있다.

> 함수 ex의 범위 안에 x가 없기 때문에 - 더 넓은 범위의 전역스코프에서 찾아온 것임.

 

왜?

자바스크립트는 변수의 범위를 호출한 함수의 지역스코프부터 전역스코프까지 점차 넓혀가며 찾기 때문임.

>> 즉, 지역 변수가 없다면 전역 변수를 호출해 오는 것임.

 

** 정확한 원리는 실행 컨텍스트 에서 추후 언급예정.

 

 


 

 

전역변수와 지역변수의 관계에서 

스코프 체인(Scope Chain)이라는 개념이 나온다.

 

내부함수에서는 외부함수의 변수에 접근 가능하지만, 
외부함수에서는 내부함수의 변수에 접근할 수 

 

var myName = 'thisisyjin';
function outer() {
	console.log(myName);
	function inner() {
    	var yourName = 'injung';
        console.log(myName);
    }
    inner();  
}
outer();
console.log(yourName);    //undefined

inner()함수는 myName이라는 변수를 찾기 위해서

1. 자신의 스코프에서 찾음 

2. outer()함수 스코프에서 찾음

3. 전역스코프에서 찾음

위와 같은 순서대로 변수를 찾게 된다.

 

이렇게 꼬리를 물고 계속 범위를 넓히면서 찾는 관계를 스코프체인 이라고 한다.

 

 

+) 외부함수인 outer에서는 내부함수 inner의 변수를 찾지 못하므로 

위 예제의 마지막줄은 undefined가 되는 것임.

 

 

 

 


 

 

💡 주의! 스코프는 '호출'할 때가 아니라 '선언'할 때 생김.

 

cf> 실행 컨텍스트는 함수를 호출할 때 생김.

var name = 'zero';    // 전역변수 name 
function log() {
  console.log(name);    // 'zero'
}

function wrapper() {    
  name = 'nero';       // 전역변수 name의 값 변경
  log(); 			   // log()함수에 의해 전역변수 name 출력
}
wrapper();           

// RESULT |  'nero'

 

log()로 log함수를 호출하기 전에 전역변수 name을 'nero'로 바꾸었으므로

결과는 nero가 된다.

 

var name = 'zero';	 // 전역변수 name
function log() {
  console.log(name);
}

function wrapper() {
  var name = 'nero';   // wrapper 내의 지역변수 name 선언
  log();               // log()호출함. 전역변수 name을 로그함
}
wrapper();

// RESULT |  'zero'

log안의 name은 전역변수 name을 의미하므로, 정답은 zero가 된다.

이런것을 Lexical Scoping이라고 한다. (= 어휘 스코프 / 정적 스코프)

 

함수를 선언하는 순간, 함수 내부의 변수는 자기 스코프 상위범위에서 참조하게 된다. = 가까운 곳

위 예시에서는 log 함수안에 name은 전역변수 name을 참조하였다.

그래서 wrapper 의 log()를 호출해서 지역변수 name='nero'를 참조하지 않고 전역변수 name을 참고한 것.

 


 

 

💡 그렇다면, 왜 전역변수 만드는 것을 삼가야할까?

변수가 섞일 수 있기 때문.

 

** 해결방법 - 전역 변수 대신 함수 안에 넣어 지역변수로 만들면 됨.

                - 또는 객체 안의 속성(property)으로 만들 수 있음.

 

예>

 

var obj = {
    x: 'local',
    y: function() {
    console.log(this.x);
    }
 }

위와 같이 하면 obj.x나 obj.y()와 같이 접근해야 하므로 

다른 변수나 함수와 섞이는 문제를 해결할 수 있다.

 

>> 이런 방법을 네임스페이스를 만든다고 표현함.

- obj라는 고유 네임스페이스를 만들어서 겹치지 않도록.

- 대부분의 라이브러리가 네임스페이스를 사용중.

예> naver는 jindo / facebook은 FB / jquery는 jQuery(또는 $)

 

 

 

 

 


REFERENCE

https://www.zerocho.com/category/Javascript/post/5740531574288ebc5f2ba97e

 

(JavaScript) 함수의 범위(scope) - lexical scoping

안녕하세요. 이번 시간에는 함수 스코프(scope)에 대해서 설명드리겠습니다. 스코프는 범위라는 뜻입니다. 전역 변수와 지역 변수 자바스크립트에서 주로 변수를 사용해 데이터를 저장했었는데

www.zerocho.com

이 포스팅은 zerocho님의 javascript 강의를 보고 작성한 글입니다.

공부+기록 용으로 작성한 것이며, 자세한 것은 위 포스팅을 참고하세요!