질문 제목:
JavaScript에서 변수의 범위는 무엇입니까?
질문 내용:
javascript에서 변수의 범위는 무엇입니까? 함수 외부와 달리 내부에 동일한 범위가 있습니까? 아니면 중요합니까? 또한 전역적으로 정의된 변수는 어디에 저장됩니까?
해결 답변:
TLDR
JavaScript에는 어휘(정적이라고도 함) 범위 지정 및 클로저가 있습니다. 즉, 소스 코드를 보면 식별자의 범위를 알 수 있습니다.네 가지 범위는 다음과 같습니다.
- 글로벌 - 모든 것이 볼 수 있음
- 기능 - 기능(및 해당 하위 기능 및 블록) 내에서 볼 수 있습니다.
- 블록 - 블록(및 해당 하위 블록) 내에서 볼 수 있습니다.
- 모듈 - 모듈 내에서 볼 수 있음
전역 및 모듈 범위의 특수한 경우를 제외하고 변수는
var
(함수 범위),
let
(블록 범위) 및
const
(블록 범위)를 사용하여 선언됩니다. 대부분의 다른 형식의 식별자 선언에는 엄격 모드에서 블록 범위가 있습니다.
개요
범위는 식별자가 유효한 코드베이스의 영역입니다.어휘 환경은 식별자 이름과 이와 관련된 값 간의 매핑입니다.범위는 상위 실행 컨텍스트의 어휘 환경에 해당하는 중첩의 각 수준과 함께 어휘 환경의 연결된 중첩으로 구성됩니다.이러한 연결된 어휘 환경은 범위 "체인"을 형성합니다. 식별자 확인은 이 체인을 따라 일치하는 식별자를 검색하는 프로세스입니다.식별자 확인은 한 방향, 즉 바깥쪽으로만 발생합니다. 이런 식으로 외부 어휘 환경은 내부 어휘 환경을 "볼" 수 없습니다.JavaScript 에서 식별자 의
를 결정하는 세 가지 관련 요소가 있습니다 .
식별자를 선언할 수 있는 몇 가지 방법은 다음과 같습니다.
var
,let
그리고const
- 기능 매개변수
- 캐치 블록 매개변수
- 함수 선언
- 명명된 함수 표현식
- 전역 개체에 대해 암시적으로 정의된 속성(예:
var
엄격하지 않은 모드에서 누락됨) import
진술eval
일부 위치 식별자는 다음과 같이 선언할 수 있습니다.
- 글로벌 컨텍스트
- 함수 본문
- 일반 블록
- 제어 구조의 맨 위(예: 루프, if, while 등)
- 제어 구조 본체
- 모듈
선언 스타일
바르
를 사용하여 선언된 식별자는 전역 컨텍스트에서 직접 선언되는 경우를 제외하고
var
함수 범위 를 가집니다. 이 경우 전역 개체의 속성으로 추가되고 전역 범위를 갖습니다.
함수 에서 사용하기 위한 별도의 규칙이 있습니다
eval
.
let과 const
식별자를 사용하여 선언
let
하고
const
블록 범위
를 가집니다. 단, 전역 컨텍스트에서 직접 선언되는 경우에는 전역 범위를 갖습니다.참고:
let
,
const
및
var
모두 게양
됩니다. 이는 정의의 논리적 위치가 둘러싸는 범위(블록 또는 함수)의 맨 위에 있음을 의미합니다.
let
그러나 를 사용 하여 선언된 변수는
const
컨트롤이 소스 코드의 선언 지점을 통과할 때까지 읽거나 할당할 수 없습니다. 임시 기간은 일시적 데드 존으로 알려져 있습니다.
function f() {
function g() {
console.log(x)
}
let x = 1
g()
}
f() // 1 because x is hoisted even though declared with `let`!
함수 매개변수 이름
함수 매개변수 이름은 함수 본문으로 범위가 지정됩니다. 여기에는 약간의 복잡성이 있습니다. 기본 인수로 선언된 함수 는 함수 본문이 아니라
함수 선언
함수 선언에는 엄격 모드의 블록 범위와 엄격하지 않은 모드의 함수 범위가 있습니다. 참고: 비엄격 모드는 다양한 브라우저의 기발한 역사적 구현을 기반으로 하는 복잡한 긴급 규칙 집합입니다.
명명된 함수 표현식
명명된 함수 표현식은 자체적으로 범위가 지정됩니다(예: 재귀를 위해).
전역 개체에 대해 암시적으로 정의된 속성
비엄격 모드에서는 전역 개체가 범위 체인의 맨 위에 있기 때문에 전역 개체에 대해 암시적으로 정의된 속성은 전역 범위를 가집니다. 엄격 모드에서는 허용되지 않습니다.
평가
문자열에서 를 사용 하여
eval
선언된 변수는
var
현재 범위에 배치되거나
eval
간접적으로 사용되는 경우 전역 개체의 속성으로 배치됩니다.
예
x
다음은 이름 ,
y
및
z
이 함수 외부에서 의미가 없기 때문에 ReferenceError 를 발생시킵니다
f
.
function f() {
var x = 1
let y = 1
const z = 1
}
console.log(typeof x) // undefined (because var has function scope!)
console.log(typeof y) // undefined (because the body of the function is a block)
console.log(typeof z) // undefined (because the body of the function is a block)
y
다음은 및 에 대한 ReferenceError를 발생
z
시키지만
x
의 가시성이
x
블록에 의해 제한되지 않기 때문에 에 대해서는 발생하지 않습니다.
if
,
for
및 와 같은 제어 구조의 본문을 정의하는 블록은
while
유사하게 동작합니다.
{
var x = 1
let y = 1
const z = 1
}
console.log(x) // 1
console.log(typeof y) // undefined because `y` has block scope
console.log(typeof z) // undefined because `z` has block scope
다음 은 함수 범위가
x
있기 때문에 루프 외부에서 볼 수 있습니다 .
var
for(var x = 0; x < 5; ++x) {}
console.log(x) // 5 (note this is outside the loop!)
var
...이 동작 때문에 in 루프 를 사용하여 선언된 변수를 닫을 때 주의해야 합니다 .
x
여기에 선언 된 변수의 인스턴스는 하나뿐이며 논리적으로 루프 외부에 있습니다.다음은
5
, 를 다섯 번 인쇄한 다음 루프 외부에
5
대해 여섯 번째 를 인쇄합니다.
console.log
for(var x = 0; x < 5; ++x) {
setTimeout(() => console.log(x)) // closes over the `x` which is logically positioned at the top of the enclosing scope, above the loop
}
console.log(x) // note: visible outside the loop
다음 은 블록 범위
undefined
이기 때문에 인쇄됩니다.
x
콜백은 하나씩 비동기적으로 실행됩니다. 변수 에 대한 새로운 동작은
let
각 익명 함수가 이름이 다른 변수에 대해 닫혀 있음을 의미합니다
x
( 로 수행했을 때와 다름 ). 따라서 ~까지 의
var
정수 가 인쇄됩니다.
0
4
for(let x = 0; x < 5; ++x) {
setTimeout(() => console.log(x)) // `let` declarations are re-declared on a per-iteration basis, so the closures capture different variables
}
console.log(typeof x) // undefined
ReferenceError
다음은 의 가시성이
x
블록에 의해 제한되지 않기 때문에 를 던지지 않습니다. 그러나
undefined
변수가 초기화되지 않았기 때문에(
if
명령문으로 인해) 인쇄됩니다.
if(false) {
var x = 1
}
console.log(x) // here, `x` has been declared, but not initialised
for
다음을 사용하여 루프 맨 위에서 선언된 변수는 루프
let
본문으로 범위가 지정됩니다.
for(let x = 0; x < 10; ++x) {}
console.log(typeof x) // undefined, because `x` is block-scoped
ReferenceError
의 가시성이
x
블록에 의해 제한 되기 때문에 다음은 오류 를 발생시킵니다.
if(false) {
let x = 1
}
console.log(typeof x) // undefined, because `x` is block-scoped
또는
var
를 사용하여 선언된 변수 는 모두 모듈로 범위가 지정됩니다.
let
const
// module1.js
var x = 0
export function f() {}
//module2.js
import f from 'module1.js'
console.log(x) // throws ReferenceError
var
다음은 전역 컨텍스트 내에서 사용하여 선언된 변수가 전역 객체에 속성으로 추가되기 때문에 전역 객체에 대한 속성을 선언 합니다.
var x = 1
console.log(window.hasOwnProperty('x')) // true
let
전역
const
컨텍스트에서 전역 개체에 속성을 추가하지 않지만 여전히 전역 범위를 가집니다.
let x = 1
console.log(window.hasOwnProperty('x')) // false
함수 매개변수는 함수 본문에서 선언된 것으로 간주할 수 있습니다.
function f(x) {}
console.log(typeof x) // undefined, because `x` is scoped to the function
Catch 블록 매개변수는 catch-block 본문으로 범위가 지정됩니다.
try {} catch(e) {}
console.log(typeof e) // undefined, because `e` is scoped to the catch block
명명된 함수 식은 식 자체로만 범위가 지정됩니다.
(function foo() { console.log(foo) })()
console.log(typeof foo) // undefined, because `foo` is scoped to its own expression
엄격하지 않은 모드에서 전역 개체에 대해 암시적으로 정의된 속성은 전역 범위가 지정됩니다. 엄격 모드에서는 오류가 발생합니다.
x = 1 // implicitly defined property on the global object (no "var"!)
console.log(x) // 1
console.log(window.hasOwnProperty('x')) // true
엄격하지 않은 모드에서 함수 선언에는 함수 범위가 있습니다. 엄격 모드에서는 블록 범위가 있습니다.
'use strict'
{
function foo() {}
}
console.log(typeof foo) // undefined, because `foo` is block-scoped
내부 작동 방식
범위는 식별자가 유효한 코드 의
JavaScript에서 모든 함수 개체에는 생성된 실행 컨텍스트 (스택 프레임) 의 어휘 환경 에
[[Environment]]
대한 참조인 숨겨진 참조가 있습니다.함수를 호출하면 숨겨진
[[Call]]
메서드가 호출됩니다. 이 메서드는 새 실행 컨텍스트를 만들고 새 실행 컨텍스트와 함수 개체의 어휘 환경 사이에 링크를 설정합니다.
[[Environment]]
함수 개체의 값을 새 실행 컨텍스트의 어휘 환경에 있는
필드로 복사하여 이를 수행합니다.새 실행 컨텍스트와 함수 개체의 어휘 환경 사이의 이 링크를
라고 합니다 .따라서 JavaScript에서 범위는 외부 참조에 의해 "체인"으로 함께 연결된 어휘 환경을 통해 구현됩니다. 이 어휘 환경 체인을 범위 체인이라고 하며 식별자 확인 은 일치하는 식별자에 대한
자세히 알아
댓글