본문 바로가기

JavaScript/ETC

렉시컬 스코핑

Q1

var name = 'zero';

function log() { console.log(name); } function wrapper() { name = 'nero'; log(); } wrapper();


정답 : nero


Q2

var name = 'zero';
function log() { console.log(name); } function wrapper() { var name = 'nero'; log(); } wrapper();

정답 : zero


Q2 log 안의 name은 wrapper 안의 지역변수 name이 아니라, 전역변수 name을 가리키고 있다. 이런것을 lexical scopping이라고 한다.


함수를 처음 선언하는 순간, 함수 내부의 변수는 자기스코프로부터 가장 가까운 곳에 있는 변수를 계속 참조하게 된다. Q2의 예시에서는 log 함수 안의 name 변수는 선언 시 가장 가까운 전역변수 name을 참조한게 된다. 그래서 wrapper 안에서 log를 호출해도 지역변수 name='nero'를 참조 하는게 아니라 그대로 전역변수 name의 값인 zero가 나오는 것이다.


전역변수는 변수가 섞일 수 있기 때문에 만드는 것을 지양해야 한다. 자바스크립트 앱을 만들면서 혼자만 개발하는 게 아니라, 여러 명과 협동도  하고, 다른 사람의 라이브러리를 사용하는 일도 많다. 그런데 전역변수를 사용하다 보면, 우연의 일치로 인해 같은 변수 이름을 사용해서 이전에 있던 변수를 덮어쓰는 불상사가 발생할 수 있다.


간단한 해결 방법은 전역 변수 대신 한번 함수 안에 넣어 지역변수로 만드는 것이다. 아니면 객체 안의 속성으로 만들 수도 있다.


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


위 처럼 하면 obj.x, obj.y() 이렇게 접근해야 하기 때문에 obj를 통째로 덮어쓰지 않는 이상은 다른 사람과 섞일 염려가 없다. 전역변수를 하나로 최소화해서 변수가 겹칠 우려도 최소화 하는 것이다.


이러한 방법을 네임스페이스를 만든다고 표현한다. obj라는 고유 네임스페이스를 만들어서 겹치지 않게 하는 것이다. naver는 jindo, facebook은 FB, jqurey는 jQuery(또는 $) 같이 대부분의 라이브러리가 네임 스페이스를 사용하고 있다. 


하지만 위 방법의 단점은 고의적으로 누군가 코드 밑에 스크립트를 추가해서 x와 y를 바꿀 수 있다. obj를 통째로 바꾸지 않더라도 밑에 obj.x = 'hacked'; 라고한 줄 추가만 하면 obj.y();를 했을 시 local 대신 hacked가 alert 된다. 그것을 방지하려면 


var another = function () { var x = 'local'; function y() { alert(x); } return { y: y }; } var newScope = another();


위와 같이  하면 된다. another();을 하는 순간 return 에 의해 { y: function () { alert(x) } }; 가 newScope에 저장된다. 이제 newScope라는 네임스페이스를 통해서 y를 접근할 수 있다. x는 접근할 수 없다. 위처럼 함수로 감싼 후 return을 통해 공개할 변수 (y)만 공개하고 비공개할 변수 (x) 는 비공개하는 방법을 취할 수 있다. 즉, return 하는 변수는 공개 변수고, 다른 것은 비공개 변수이다.


위의 코드를 간략하게 바꾸면


var newScope = (function () { var x = 'local'; return { y: function() { alert(x); } }; })();


위와 같이 쓸 수 있다. another 같은 변수를 한 번 거치는 대신, newScope에 바로 집어넣는 것이다. (function(){})(); 구문은 IIFE(즉시 호출 함수 표현식)이라고도 하고, 모듈 패턴이라고 하는데, 함수를 선언하자마자 바로 실행시켜버리는 것이다. 함수를 function(){}로 선언하면서 동시에 ()를 붙이니깐 즉시 실행된다. 이 구문이 라이브러리를 만들 때 기본이다. 많은 라이브러리가 이 구문을 활용하고 있다. 비공개 변수가 없는 자바스크립트에 비공개 변수 기능을 만들어주기 때문이다. 


출처 : https://www.zerocho.com/category/JavaScript/post/5740531574288ebc5f2ba97e

'JavaScript > ETC' 카테고리의 다른 글

불변성  (0) 2019.04.03
Object.entries()  (0) 2019.03.29
자바스크립트 비동기 처리와 콜백함수  (0) 2019.03.07
async.js  (0) 2019.03.06
this  (0) 2019.03.05