변수 접근 규칙에 따른 유효 범위
Function Scope vs Global Scope
var은 함수단위로 자신만의 scope를 가진다(Function Scope), 재선언과 재할당이 가능하다.
const 은 let 과 동일하게 'Block Scope'를 가진다.
const는 재선언 및 재할당을 할 수 없다.
let은 재선언을 못한다.
전역범위를 대표하는 객체 window는
Global Scope에서 선언된 함수이다.
(var로 변수를 선언하면 window객체와 연결된다. 남발하면 컴퓨터 날아간다...)
하지만 let과 const는 담기지 않는다.
클로저(closure)는 내부함수가 외부함수의 맥락(context)에 접근할 수 있는 것을 가르킨다. 클로저는 자바스크립트를 이용한 고난이도의 테크닉을 구사하는데 필수적인 개념으로 활용된다.
함수와 함수가 선언된 어휘적 환경의 조합.
이환경은 클로저가 생성된 시점의 유효범위 내에 있는 모든 지역 변수로 구성된다.
코딩에서 lexical(어휘적) : 눈베 보이는 데로, ’사전식’
클로져는 외부함수의 변수에 접근할 수 있는 내부함수이다.
여기서 innerfn에 접근 가능한 scope범위는 총 3개다 (local, global, inner파트)
함수(outer)안에 함수(inner)를 쓰면 inner함수는 밖에서 쓸 수 없다.
만약 밖에서 함수를 사용할 수 있다면 응집성이 떨어지게된다.
반대로 생각하면 함수안에 함수를 쓴다면 다른 요소의 개입이 줄어들고,
눈에 보기도 편하게 된다.
또한, 자바스크립트가 private한 변수를 쓸 수 있게 해주는 좋은 메커니즘.
function outer(){
var title = 'coding everybody'; //외부함수에 정의되어진 지역변수
function inner(){
alert(title); //함수 밖에서 찾는다.
}
inner();
}
outter();
**내부함수에서 정의된 title이 없다면 함수 밖에서 title을 찾게된다.
즉, 이처럼 내부함수에서 외부함수의 지역변수로 접근할 수 있는데,
이것을 클로져라고 부른다.
function outter(){
var title = 'coding everybody';
return function(){
alert(title);
}
}
let inner = outter();
inner();
클로저의 중요한 특징 중 하나는
현재 outter() 함수를 inner 에 넣어주게 되면 outter()함수의 리턴 값이
return function(){alert(title);} inner에 들어가게된다.
그리고 outter()함수는 리턴을 함으로써 함수의 생을 마감할 것 같지만
inner변수를 함수로써 실행하게되면(inner()) 다시 title을 찾아 외부함수의 지역변수 값에 접근 할 수 있다는 중요한 특징이 있다.
즉 inner()는 결과 값 'coding everybody'을 실행하게 된다.
클로저의 또 하나의 특성은 변수를 private하게 만드는 점이다.
function factory_movie(title){
return {
get_title : function (){
return title; // 지역 변수 title 가르킴
},
set_title : function(_title){
title = _title // 지역 변수 title 가르킴
}
}
}
ghost = factory_movie('Ghost in the shell');
matrix = factory_movie('Matrix');
alert(ghost.get_title());
alert(matrix.get_title());
ghost.set_title('공각기동대'); //ghost의 셋 타이틀 ***
alert(ghost.get_title()); // ghost셋타이틀에의해 결과 값이 바뀜 '공각 기동대'
alert(matrix.get_title()); // 아무짓도 안해서 똑같음
함수를 이런식으로 바로 return {} 객체를 써버리게 되면 얻는 이점으로는 이 함수가 가지고있는 지역 변수 title은 내부에서 get_title 메서드와 set_title 메서드에서만 접근 할 수 있으며, 만약 다른 사람에 의해 메서드를 어떻게 쓰든 내부 내용은 바뀌지 않는 다는 점이다.
var arr = []
for(var i = 0; i < 5; i++){ //return i는 이쪽 i++를 가르킨다
arr[i] = function(){
return i;
}
}
for(var index in arr) {
console.log(arr[index]()); // 5만 5번 출력
}
왜 5만 5번 출력되었을까?
arr[i]의 함수 function()의 i는 전역 변수 for()문 안의 var i를 가르키기 때문이다. (호출 할 당시의 i 값을 가져온다.) => i값은 먼저 함수내부에 i가있나 확인하고 있으면 그걸쓰고 없으면 외부에서 찾는데 결과 적으로 최종 i값(5)을 가져오게 된다.
클로저의 특성을 이해했다면 전역 변수 i 값이 아닌 함수를 하나 더 만들어 주고 지역 변수로 return 값을 가져온다면 해결 할 수 있다.
var arr = []
for(var i = 0; i < 5; i++){
arr[i] = function(id) {
return function(){
return id; //지역변수 id를 가르킴
}
}(i); // **함수 바로 실행 **
}
for(var index in arr) {
console.log(arr[index]()); // 0 1 2 3 4 출력
}
참고
https://opentutorials.org/course/743/6544
https://developer.mozilla.org/ko/docs/JavaScript/Guide/Closures
http://ejohn.org/apps/learn/#48
http://blog.javarouka.me/2012/01/javascripts-closure.html