scope
스코프란?
변수가 유효한 범위가 있다.
범위는 중괄호(블록) 또는 함수에 의해 나누어지고, 그 범위를 스코프라고 부른다.
바깥쪽 스코프에서 선언한 변수는 안쪽 스코프에서 사용 가능하다.
반면에, 안쪽에서 선언한 변수는 바깥쪽 스코프에서는 사용할 수 없다.
또, 스코프는 중첩이 가능하다. 마치 중첩된 울타리와 같다.
javascript에서 함수는 실행이 아니라, 정의된 곳에서 스코프를 찾아야한다.
이것을 static scope(정적스코프), lexical scope(어휘적스코프)라 한다.
반대의 경우 dinamic scope라 한다.
전역스코프 & 지역스코프
특별히 가장 바깥쪽의 스코프는 전역 스코프(Global Scope)
전역이 아닌 다른 스코프는 전부 지역 스코프(local scope)
지역 변수는 해당 지역에서 전역 변수보다 더 높은 우선순위를 가진다.
하지만
스코프 밖에 나가서 지역 변수를 사용하면 ReferenceError가 나온다.
쉐도잉 variable shadowing
let name = '김코딩';
function showName() {
let name = '박해커'; // 지역 변수
console.log(name); // 두 번째 출력
}
console.log(name); // 첫 번째 출력
showName();
console.log(name); // 세 번째 출력
전역변수 name은 김코딩, 지역변수 name은 박해커가 할당되어 있다. 지역변수의 스코프인 함수 showName을 출력하면 지역변수 name에 할당된 박해커가 나오지만, 함수 바깥 스코프에서는 전역변수에 할당된 김코딩이 출력된다. 변수 이름이 전역 변수와 똑같지만, 지역 변수가 전역 변수보다 우선순위가 높으므로, 지역 변수 name이 출력되는 것. 동일한 변수 이름으로 인해 바깥쪽 변수가 안쪽 변수에 의해 가려지는(shadow) 이러한 현상이 쉐도잉(variable shadowing)
지역변수를 선언하지 않은 경우
let name = '김코딩';
function showName() {
name = '박해커';
console.log(name); // 두 번째 출력
}
console.log(name); // 김코딩
showName(); //박해커
console.log(name); // 박해커
앞서 문제와는 다르게, 세 번째 줄에서 let 키워드를 사용한 선언이 존재하지 않습니다.
이는, '박해커'라는 값으로 할당하고 있는 name 변수는 전역에 선언된 name 변수를 그대로 사용하겠다는 의미입니다.
지역 스코프에서 새로 선언되지 않으면 그냥 같은 변수입니다.
따라서 showName 함수가 실행되기 전, 처음에는 '김코딩'을 출력하고, 그 이후에는 전역변수 name의 값이 바뀌기 때문에 두 번째 및 세 번째 출력에 '박해커'가 출력됩니다.
스코프의 종류
블록 스코프
중괄호를 기분으로 범위 구분
* 화살표 함수는 함수임에도 블록스코프로 취급됨
함수 스코프
function 키워드가 등장하는 함수 선언식 및 함수 표현식
함수의 실행부터 종료까지가 함수 스코프의 범위
*화살표 함수 제외!!
변수선언 키워드의 차이점
let은 재선언 시 에러 알려줌(재할당 가능). const은 재선언, 재할당 모두 불가. var는 모두 가능.
var의 특성
var는 재선언 해도 에러가 나지 않는다.
var는 무조건 전역 변수가 아니다. 가장 바깥 스코프에 선언해야만 전역 변수이다.
var로 선언한 전역 변수는 window 객체에 저장된다. (let, const는 아님)
var는 {블록스코프}를 무시한다. 하지만 함수 스코프와 화살표함수의 블록스코프는 따른다.
함수 스코프+화살표함수(블록스코프) 경우에도 전역 <-> 지역, 함수 안팎의 순서를 유의해서 따지자.
window 객체
var로 선언한 전역변수 및 전역함수는 window 객체에 속하게 된다
*var로 선언하면 모두 전역변수라는 의미가 아님 *
개발자 도구를 열어 콘솔에 window 라고 입력해 보세요. 객체 하나를 조회할 수 있습니다.
이 객체는 사실 브라우저의 창(window)을 의미하는 객체이지만, 이와 별개로 전역 영역을 담고 있기도 함.
함수 선언식으로 함수를 선언하거나, var로 전역 변수를 만들면, window 객체에서도 동일한 값을 찾을 수가 있다.
" window.변수명 " 의 형태로 사용.
side effect
전역변수가 너무 많으면 다른 함수, 혹은 로직에 의해 의도되지 않은 변경이 발생할 수 있다. 이를 side effect 라고 한다. 전역변수를 최소화 하여 side effect를 줄여야한다. 전역 변수를 var로 선언하는 것은 브라우저의 내장 기능을 사용하지 못하게 만들 수도 있다. 때문에 let을 사용하는 것이 좋다!
'use strict'
선언 키워드 없이 변수를 할당하면 해당 변수는 var로 선언한 전역 변수처럼 취급된다.
선언 키워드 없는 선언은 최고 스코프에 선언됩니다. 함수 내에서 선언 키워드 없는 선언은, 함수의 실행 전까지 선언되지 않은 것으로 취급합니다. -> 이 부분은 더 생각해보자
Strict Mode는 브라우저가 보다 엄격하게 작동하도록 함. "선언 없는 변수 할당"의 경우도 Strict Mode는 에러로 판단합니다. Strict Mode를 적용하려면, js 파일 상단에 'use strict' 라고 입력. (따옴표 포함)
예제
let x = 10;
function outer () {
x = 20;
function inner () {
x = x + 20;
}
inner();
}
outer();
let result = x;
//result = 40
//inner는 inner() 이 부분에서 실행된다.