스코프
변수와 상수, 매개변수가 언제 어디서 정의되는지를 결정
ex ) 함수 매개변수가 함수 바디 안에서만 존재하는 것
1 | //스코프 |
x가 아주 잠시나마 존재했으므로 x + 3을 계산 할 수 있었다. 그러나 함수를 벗어나면 x가 존재하지 않는 것처럼 보인다. 따라서 x의 스코프가 함수 f라고한다.
- 스코프 : 시야, 범위라고 이해
변수의 스코프가 어떤 함수라고 말할 때, 함수를 실제 호출할 때 까지는 함수 바디의 정해진 매개변수가 존재하지 않는다. 함수를 호출할 때마다 매개변수가 나타나고, 함수가 제어권을 반환하면 스코프 밖으로 사라진다.
변수와 상수는 만들기 전에는 존재하지 않는다. let이나 const로 선언 하기 전에는 스코프 안에서 존재하지 않는다.
(var는 특수한 경우)
변수를 선언 : 식별자를 주어서 존재를 알린다.
변수를 정의 : 선언과 함께 값을 부여한다.
자바스크립트는 선언과 동시에 값이 주어지므로 둘을 구분하지 않는다.
7.1 스코프와 존재
변수가 존재하지 않으면 그 변수는 스코프안에 ‘있지 않음’ → 그 변수는 존재하지 않는다 ?
꼭 그런건 아님
스코프 : 실행 컨텍스트에서 현재 보이고 접근할 수 있는 식별자
존재한다 : 그 식별자가 메모리가 할당된 무언가를 가리킴
‘존재하지만 스코프 안에는 없는 변수의 예’
무언가가 더 존재하지 않는다 해도 자바스크립트는 메모리를 바로 회수하는 것이 아닌,
자동적으로 가비지 콜렉션 프로세스에서 메모리를 회수 한다.
7.1 정적 스코프와 동적 스코프
1 | function f1(){ |
정적으로 보면 이 프로그램은 위에서 아래로 읽어내리지만(f1 정의-> f2정의) 실행을 하면 f2 -> f1 -> f2 자바스크립트의 스코프는 정적, 어떤 변수가 함수 스코프 안에 있는지 함수를 정의할 때 알 수 있다.
1 | const x = 3; |
1. 변수 x는 함수 f를 정의 할 때 존재하나 y는 다른 스코프에도 존재 한다.
2. 다른 스코프에서 y를 선언하고 그 스코프에서 f를 호출하더라도
f를 호출하면 x는 그 바디 안에 스코프에 있지만 y는 그렇지 않다.
3. 정적 스코프는 전역 스코프, 블록 스코프 , 함수 스코프에 적용된다.
7.3 전역 스코프
스코프는 계층적이며 트리 맨아래 바탕이 되는 무언가가 있어야 한다.
-> 암시적으로 주어지는 스코프가 필요
이를 전역 스코프 라고 한다.
전역 스코프에서 선언한 것은 무엇이든 프로그램의 모든 스코프에서 볼 수 있다.
전역변수 : 전역 스코프에서 선언된 것 , 전역 스코프에 의존하는 걸 피해라..
1 | //전역 스코프, 전역변수 |
1. 함수가 호출하는 스코프에 대단히 의존적이다
2. name과 age의 값을 어디든지 실수로 바꿀 수 있다.
3. greet()와 getBirthYear()도 전역 변수에 의존하므로
name과 age를 정확히 사용한다는 가정에서만 쓸 수 있다.
1 | //전역 스코프, 전역변수 개선ver1 |
1. user을 써서 단일 객체에 보관 2. 그러나 아직 greet와 getBirthYear은 전역 user에 의존
1 | //전역 스코프, 전역변수 개선ver2 |
1. 모든 스코프에서 호출할 수 있고, 명시적으로 user을 전달 받음
7.4 블록 스코프
블록의 스코프안에서만 보이는 식별자
let,const는 식별자를 블록 스코프에서 선언
1 | //블록 스코프 |
x는 블록 안에서 정의되었고, 블록을 나가는 즉시 x도 스코프 밖으로 사라지므로 정의되지 않은 것으로 간주
7.5 변수 숨기기
다른 스코프에 있으면서 이름이 같은 변수나 상수는 혼란을 초래
1 | { |
변수 숨기기
1 | //스코프 중첩 |
1. 내부 블록의 x와 외부블록의 x는 이름만 같은 다른 변수이다. 2. 그러므로 외부 스코프의 x를 숨기는 (가리는) 효과를 발휘 3. 실행 흐름이 내부 블록에 들어가 새 x를 정의 할 때, 두 변수가 모두 스코프 안에 있다 4. 이름이 같은 x의 경우 내부 블록에서 외부 스코프에 접근 할 방법은 없음
1 | { |
1. 스코프는 계층적 , 이로인해 스코프 체인이란 개념이 생김
2. 스코프 체인에 있는 변수는 스코프에 있는 것이므로 숨겨지지만 않으면 접근이 가능하다.
7.6 함수, 클로저, 정적 스코프
함수가 특정 스코프에 접근할 수 있도록 의도적으로 그 스코프에서 정의하는 경우가 많다.
이를 클로저라고 한다.
클로저 : 스코프를 함수 주변으로 좁히는 것
1 | //클로저 예제 |
1. globalFunc가 블록 안에서 값을 할당 받음 2. globalFunc를 호출하면 이 함수는 스코프에서 빠져나왔어도 blockVar에 접근 할 수 있다. 3. 일반적으로 스코프를 빠져나가면 해당 스코프 안에서 선언한 변수는 메모리에서 제거해도 안전하다 4. 그러나 스코프 안에서 함수를 정의했고, 이 함수는 스코프 밖에서도 참조할 수 있으므로 자바스크립트는 스코프를 계속 유지한다. => 즉, 스코프 안에서 함수를 정의하면 해당 스코프는 더 오래 유지가 된다 . => 또한, 접근 할 수 없는 것에 접근 할 수 있게하는 효과도 있다.
1 | let f; //정의되지 않은 함수 |
1. 일반적으로 스코프 바깥쪽에 있는 것들은 접근할 수 없다. 2. 그러나 함수를 정의해 클로저를 만들면 접근할 방법이 생긴다 .
7.7 즉시 호출하는 함수 표현식
함수 표현식을 사용하면 즉시 호출하는 함수 표현식(llEF)를 만들 수 있다.
IIFE : Immediately Invoked Function Expressions, 함수를 선언하고 즉시 실행
1 | //IIEF |
함수 표현식으로 익명 함수를 만들고 그 함수를 즉시 호출 IIFE는 내부에 있는 것 모두 자신의 스코프를 가지지만, IIEF가 함수이므로 스코프 밖으로 무언갈 내보낼 수 있는 장점을 가짐
1 | const message =(function(){ |
1. 변수 secret은 IIEF 스코프 안에서 안전하게 보호되며 외부에서 접근 할 수 없다. 2. 그렇지만 IIEF는 함수이므로 무엇이든 반환할 수 있다.
1 | const f = (function(){ |
변수 count는 IIEF안에 안전하게 보관되어 있으므로 손댈 방법이 없다. f는 자신이 몇 번 호출됐는지 정확히 알고 있다.
7.8 함수 스코프와 호이스팅
let
let으로 변수를 선언하면, 그 변수는 선언하기 전에 존재하지 않는다.
var
var로 선언한 변수는 현재 스코프 안이라면 어디서든 사용할 수 있으며, 선언하기 전에도 사용할 수 있다.
아직 선언되지않은 변수의 값 == 에러를 일으킴
존재하되 값이 undefined인 변수 = 에러를 일으키지 않음
1 | //let |
1. var로 변수를 선언하면, 선언하기 전에도 사용할 수 있다. 2. var로 선언한 변수는 끌어올린다는 뜻의 호이스팅이라는 메커니즘을 따름 3. 선언만 끌어올리지며, 할당은 끌어올리지지 않는다.
1 | //원래코드 |
1. 같은 함수나 전역 스코프 안에서는 var로 새 변수를 만들 수 없다. 2. let으로 가능 했던 변수 숨김도 불가능 3. 그렇지만 ES5로 트랜스 컴파일 해야하므로 var의 동작을 이해해야한다.
7.9 함수 호이스팅
var로 선언된 변수와 마찬가지로, 함수 선언도 스코프 맨 위로 끌어올려진다.
함수를 선언하기 전에 호출 할 수 있다.
1 | f(); //"f" |
그러나, 변수에 할당한 함수 표현식은 끌어올려지지 않는다.
1 | f(); //ReferrenceError : f는 정의되지 않았습니다. |
7.10 사각지대
let으로 선언하는 변수는 선언하기 전까지 존재하지 않는다는 직관적 개념
스코프 안에서 변수의 사각지대는 변수가 선언되기 전의 코드
1 | if(typeof x ==="undefined"){ |
해당 코드는 안전하고 에러가 발생하지 않는다.
BUT, 이 코드를 let으로 바꾸면 에러가 발생
1 | //사각지대 let |
ES6에서는 typeof 연산자로 변수가 정의됐는지 확인 할 필요가 거의 없어짐
7.11 스트릭트 모드
암시적 전역변수(ES5문법) : var로 변수를 선언하는 것을 잊으면 자바스크립트는 전역 변수를 참조하려 한다고 간주하고,
그런 전역변수를 스스로 생성 => 수많은 문제 생성
스트릭트 모드 : 암시적 전역 변수를 허용하지 않음
“use strict”를 코드 맨 앞에 씀
전역 스코프에서 스트릭트 모드를 사용하지 않는 편이 좋다 .
1 | (function(){ |