etc./StackOverFlow

JavaScript에서 변수의 범위는 무엇입니까?

청렴결백한 만능 재주꾼 2021. 12. 2. 00:27
반응형

질문자 :lYriCAlsSH


자바 스크립트에서 변수의 범위는 무엇입니까? 함수 외부와 달리 내부에 동일한 범위가 있습니까? 아니면 상관없나요? 또한 전역적으로 정의된 변수는 어디에 저장됩니까?



TLDR

JavaScript에는 어휘(정적이라고도 함) 범위와 클로저가 있습니다. 즉, 소스 코드를 보고 식별자의 범위를 알 수 있습니다.

네 가지 범위는 다음과 같습니다.

  1. 글로벌 - 모든 사람이 볼 수 있음
  2. 기능 - 기능(및 해당 하위 기능 및 블록) 내에서 볼 수 있음
  3. 블록 - 블록(및 해당 하위 블록) 내에서 볼 수 있습니다.
  4. 모듈 - 모듈 내에서 볼 수 있음

전역 및 모듈 범위의 특수한 경우를 제외하고 변수는 var (함수 범위), let (블록 범위) 및 const (블록 범위)를 사용하여 선언됩니다. 대부분의 다른 형식의 식별자 선언은 엄격 모드에서 블록 범위를 갖습니다.

개요

범위는 식별자가 유효한 코드베이스의 영역입니다.

어휘 환경은 식별자 이름과 식별자 이름과 관련된 값 간의 매핑입니다.

범위는 상위 실행 컨텍스트의 어휘 환경에 해당하는 중첩의 각 수준과 함께 어휘 환경의 연결된 중첩으로 구성됩니다.

이러한 연결된 어휘 환경은 범위 "체인"을 형성합니다. 식별자 확인은 이 체인을 따라 일치하는 식별자를 검색하는 프로세스입니다.

식별자 확인은 한 방향, 즉 바깥쪽으로만 발생합니다. 이런 식으로 외부 어휘 환경은 내부 어휘 환경을 "볼" 수 없습니다.

JavaScript에서 식별자 의 범위 를 결정하는 데에는 세 가지 관련 요소가 있습니다.

  1. 식별자 선언 방법
  2. 식별자가 선언된 위치
  3. 엄격 모드 인지 엄격 모드인지 여부

식별자를 선언할 수 있는 몇 가지 방법:

  1. var , letconst
  2. 기능 매개변수
  3. 캐치 블록 매개변수
  4. 함수 선언
  5. 명명된 함수 표현식
  6. 전역 객체에 대해 암시적으로 정의된 속성(즉, 엄격하지 않은 모드에서 var
  7. import
  8. eval

일부 위치 식별자를 선언할 수 있습니다.

  1. 글로벌 컨텍스트
  2. 기능 본문
  3. 일반 블록
  4. 제어 구조의 맨 위(예: 루프, if, while 등)
  5. 제어 구조 본체
  6. 모듈

선언 스타일

var

var 사용하여 선언된 식별자는 전역 컨텍스트에서 직접 선언된 경우를 제외하고 함수 범위를 가지며 , 이 경우 전역 개체의 속성으로 추가되고 전역 범위를 갖습니다. eval 기능에서 사용하기 위한 별도의 규칙이 있습니다.

let과 const

letconst 사용하여 선언된 식별자는 전역 컨텍스트에서 직접 선언된 경우를 제외하고 블록 범위 를 갖습니다. 이 경우 전역 범위가 있습니다.

참고: let , constvar 는 모두 호이스트 됩니다. 이것은 정의의 논리적 위치가 포함하는 범위(블록 또는 기능)의 맨 위에 있음을 의미합니다. letconst 사용하여 선언된 변수는 제어가 소스 코드의 선언 지점을 통과할 때까지 읽거나 할당할 수 없습니다. 잠정 기간을 임시 데드 존이라고 합니다.

 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 , yz f 외부에서 의미가 없기 때문에 다음은 ReferenceError를 발생시킵니다.

 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)

x 의 가시성이 블록에 의해 제한되지 yz 대해 ReferenceError 를 발생시키지만 x if , forwhile 과 같은 제어 구조의 본문을 정의하는 블록은 유사하게 작동합니다.

 { 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

다음은 x 가 블록 범위이기 때문에 undefined 콜백은 비동기적으로 하나씩 실행됩니다. 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

다음은 x 의 가시성이 블록에 의해 제한되지 ReferenceError 그러나 변수가 초기화 if 문으로 undefined

 if(false) { var x = 1 } console.log(x) // here, `x` has been declared, but not initialised

let 사용하여 for 루프의 맨 위에 선언된 변수는 루프의 본문으로 범위가 지정됩니다.

 for(let x = 0; x < 10; ++x) {} console.log(typeof x) // undefined, because `x` is block-scoped

다음은 x 의 가시성이 블록에 의해 제한 ReferenceError

 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

letconst 는 전역 개체에 속성을 추가하지 않지만 여전히 전역 범위를 갖습니다.

 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에서 범위는 외부 참조에 의해 "체인"으로 함께 연결된 어휘 환경을 통해 구현됩니다. 이 어휘 환경 체인을 범위 체인이라고 하며 일치하는 식별자에 대해 체인을 검색하여 식별자 확인이 발생합니다.

알아 보다 .


Triptych

Javascript는 범위 체인을 사용하여 주어진 함수의 범위를 설정합니다. 일반적으로 하나의 전역 범위가 있으며 정의된 각 함수에는 고유한 중첩 범위가 있습니다. 다른 함수 내에 정의된 모든 함수에는 외부 함수에 연결된 로컬 범위가 있습니다. 범위를 정의하는 것은 항상 소스의 위치입니다.

범위 체인의 요소는 기본적으로 상위 범위에 대한 포인터가 있는 맵입니다.

변수를 해결할 때 javascript는 가장 안쪽 범위에서 시작하여 바깥쪽으로 검색합니다.


krosenvold

전역적으로 선언된 변수에는 전역 범위가 있습니다. 함수 내에서 선언된 변수는 해당 함수로 범위가 지정되고 동일한 이름의 전역 변수를 섀도우합니다.

(I 확실히 실제 자바 스크립트 프로그래머는 다른 답변에서 지적 할 수있을 것으로 많은 미묘한가 있어요. 특히 내가 건너 온에서 이 페이지 정확히 about this 언제든지 수단. 희망 이 더 소개 링크를 시작하기에 충분입니다 그렇지만.)


Jon Skeet

올드 스쿨 자바스크립트

전통적으로 JavaScript에는 두 가지 유형의 범위만 있습니다.

  1. 전역 범위 : 변수는 응용 프로그램 시작부터 응용 프로그램 전체에 걸쳐 알려져 있습니다 (*)
  2. 기능적 범위 : 변수는 선언된 함수 내에서 함수 의 시작 부분 (*)부터 알 수 있습니다.

차이점을 설명하는 다른 답변이 이미 많이 있으므로 이에 대해 자세히 설명하지 않겠습니다.


최신 자바스크립트

최신 JavaScript 사양은 이제 세 번째 범위도 허용합니다.

  1. 블록 범위 : 식별자는 자신이 선언된 범위의 맨 위에서 "알려져" 있지만 선언 라인 이후까지 할당하거나 역참조(읽기)할 수 없습니다. 이 중간 기간을 "시간적 데드존"이라고 합니다.

블록 범위 변수는 어떻게 생성합니까?

전통적으로 다음과 같이 변수를 생성합니다.

 var myVariable = "Some text";

블록 범위 변수는 다음과 같이 생성됩니다.

 let myVariable = "Some text";

그렇다면 기능 범위와 블록 범위의 차이점은 무엇입니까?

기능 범위와 블록 범위의 차이점을 이해하려면 다음 코드를 고려하십시오.

 // i IS NOT known here // j IS NOT known here // k IS known here, but undefined // l IS NOT known here function loop(arr) { // i IS known here, but undefined // j IS NOT known here // k IS known here, but has a value only the second time loop is called // l IS NOT known here for( var i = 0; i < arr.length; i++ ) { // i IS known here, and has a value // j IS NOT known here // k IS known here, but has a value only the second time loop is called // l IS NOT known here }; // i IS known here, and has a value // j IS NOT known here // k IS known here, but has a value only the second time loop is called // l IS NOT known here for( let j = 0; j < arr.length; j++ ) { // i IS known here, and has a value // j IS known here, and has a value // k IS known here, but has a value only the second time loop is called // l IS NOT known here }; // i IS known here, and has a value // j IS NOT known here // k IS known here, but has a value only the second time loop is called // l IS NOT known here } loop([1,2,3,4]); for( var k = 0; k < arr.length; k++ ) { // i IS NOT known here // j IS NOT known here // k IS known here, and has a value // l IS NOT known here }; for( let l = 0; l < arr.length; l++ ) { // i IS NOT known here // j IS NOT known here // k IS known here, and has a value // l IS known here, and has a value }; loop([1,2,3,4]); // i IS NOT known here // j IS NOT known here // k IS known here, and has a value // l IS NOT known here

여기서 변수 j 는 첫 번째 for 루프에서만 알려져 있지만 전후에는 알 수 없습니다. 그러나 우리의 변수 i 는 전체 함수에서 알려져 있습니다.

또한, 블록 범위 변수는 호이스팅되지 않기 때문에 선언되기 전에 알 수 없다는 점을 고려하십시오. 또한 동일한 블록 내에서 동일한 블록 범위 변수를 다시 선언할 수 없습니다. 이것은 블록 범위 변수가 호이스트되고 다중 선언의 경우 오류를 생성하지 않는 전역 또는 기능 범위 변수보다 오류 발생 가능성이 적습니다.


오늘날 블록 범위 변수를 사용하는 것이 안전합니까?

오늘날 사용하는 것이 안전한지 여부는 환경에 따라 다릅니다.

  • 서버 측 JavaScript 코드( Node.js let 문을 안전하게 사용할 수 있습니다.

  • 클라이언트 측 JavaScript 코드를 작성하고 브라우저 기반 변환기(예: Traceur 또는 babel-standalone )를 사용하는 경우 let 문을 안전하게 사용할 수 있지만 코드는 성능 면에서 최적이 아닐 수 있습니다.

  • 클라이언트 측 JavaScript 코드를 작성하고 Node 기반 변환기(예: traceur 셸 스크립트 또는 Babel )를 사용하는 경우 let 문을 안전하게 사용할 수 있습니다. 그리고 브라우저는 트랜스파일된 코드에 대해서만 알기 때문에 성능상의 단점은 제한되어야 합니다.

  • 클라이언트 측 JavaScript 코드를 작성 중이고 변환기를 사용하지 않는 경우 브라우저 지원을 고려해야 합니다.

    let 을 전혀 지원하지 않는 일부 브라우저입니다.

    • 인터넷 익스플로러 10 이하
    • 파이어폭스 43 이하
    • 사파리 9 이하
    • 안드로이드 브라우저 4 이하
    • 오페라 27 이하
    • 초메 40 이하
    • 모든 버전의 Opera MiniBlackberry 브라우저

여기에 이미지 설명 입력


브라우저 지원을 추적하는 방법

이 답변을 읽는 시점에 let 문을 지원하는지에 대한 최신 개요는 Can I Use 페이지를 참조하십시오 .


(*) 전역 및 기능 범위 변수는 JavaScript 변수가 호이스트 되기 때문에 선언되기 전에 초기화 및 사용할 수 있습니다. 이것은 선언이 항상 범위의 맨 위에 있음을 의미합니다.


John Slegers

다음은 예입니다.

 <script> var globalVariable = 7; //==window.globalVariable function aGlobal( param ) { //==window.aGlobal(); //param is only accessible in this function var scopedToFunction = { //can't be accessed outside of this function nested : 3 //accessible by: scopedToFunction.nested }; anotherGlobal = { //global because there's no `var` }; } </script>

클로저를 조사하고 이를 비공개 멤버 로 만드는 방법을 조사하고 싶을 것입니다.


geowa4

내가 이해하는 핵심은 Javascript가 더 일반적인 C 블록 범위와 비교하여 기능 수준 범위를 갖는다는 것입니다.

여기에 주제에 대한 좋은 기사가 있습니다.


James McMahon

"Javascript 1.7"(Mozilla의 Javascript 확장)에서는 let 문으로 블록 범위 변수를 선언할 수도 있습니다.

 var a = 4; let (a = 3) { alert(a); // 3 } alert(a); // 4

kennytm

원래 Brendan Eich 가 설계했을 때 JavaScript의 범위 지정에 대한 아이디어 는 HyperCard 스크립팅 언어인 HyperTalk 에서 나왔습니다.

이 언어에서 표시는 색인 카드 더미와 유사하게 수행되었습니다. 배경이라고 하는 마스터카드가 있었다. 투명하고 하단 카드로 볼 수 있습니다. 이 기본 카드의 모든 콘텐츠는 그 위에 놓인 카드와 공유되었습니다. 맨 위에 놓인 각 카드에는 이전 카드보다 우선 순위가 높은 자체 콘텐츠가 있지만 원하는 경우 이전 카드에 계속 액세스할 수 있습니다.

이것이 바로 JavaScript 범위 지정 시스템이 설계된 방식입니다. 단지 이름이 다를 뿐입니다. JavaScript의 카드는 실행 컨텍스트 ECMA 로 알려져 있습니다. 이러한 각 컨텍스트에는 세 가지 주요 부분이 있습니다. 변수 환경, 어휘 환경 및 this 바인딩. 카드 참조로 돌아가서 어휘 환경에는 스택 아래에 있는 이전 카드의 모든 콘텐츠가 포함됩니다. 현재 컨텍스트는 스택의 맨 위에 있으며 거기에 선언된 모든 내용은 변수 환경에 저장됩니다. 이름 충돌의 경우 변수 환경이 우선합니다.

이 바인딩은 포함하는 개체를 가리킵니다. window 또는 생성자 함수일 수 있는 선언된 함수에서와 같이 포함 개체가 변경되지 않고 범위 또는 실행 컨텍스트가 변경됩니다.

이러한 실행 컨텍스트는 제어가 전송될 때마다 생성됩니다. 코드 실행이 시작될 때 제어가 전송되며 이는 주로 함수 실행에서 수행됩니다.

이것이 기술적인 설명입니다. 실제로 JavaScript에서 다음을 기억하는 것이 중요합니다.

  • 범위는 기술적으로 "실행 컨텍스트"입니다.
  • 컨텍스트는 변수가 저장되는 환경 스택을 형성합니다.
  • 스택의 상단이 우선합니다(하단은 전역 컨텍스트임).
  • 각 함수는 실행 컨텍스트를 생성합니다(그러나 항상 새로운 this 바인딩은 아님)

이를 이 페이지의 이전 예제(5. "Closure") 중 하나에 적용하면 실행 컨텍스트의 스택을 따를 수 있습니다. 이 예에서는 스택에 세 개의 컨텍스트가 있습니다. 그것들은 외부 컨텍스트, var 6에 의해 호출된 즉시 호출된 함수의 컨텍스트, var 6의 즉시 호출된 함수 내부의 반환된 함수의 컨텍스트에 의해 정의됩니다.

i ) 외부 컨텍스트. = 1의 가변 환경이 있습니다.
ii ) IIFE 컨텍스트는 a = 1의 어휘 환경을 갖지만 스택에서 우선하는 a = 6의 가변 환경을 갖습니다.
iii ) 반환된 함수 컨텍스트는 a = 6의 어휘 환경을 가지며 호출될 때 경고에서 참조되는 값입니다.

여기에 이미지 설명 입력


Travis J

1) 전역 범위, 함수 범위, with 및 catch 범위가 있습니다. 일반적으로 변수에 대한 '블록' 수준 범위는 없습니다. with 및 catch 문은 블록에 이름을 추가합니다.

2) 범위는 전역 범위까지 함수에 의해 중첩됩니다.

3) 프로토타입 체인을 거쳐 속성이 해결됩니다. with 문은 개체 속성 이름을 with 블록에 의해 정의된 어휘 범위로 가져옵니다.

편집: ECMAAScript 6(하모니)은 let을 지원하도록 지정되었으며 크롬이 '하모니' 플래그를 허용한다는 것을 알고 있으므로 아마도 지원합니다.

Let은 블록 수준 범위 지정을 지원하지만 이를 수행하려면 키워드를 사용해야 합니다.

편집: Benjamin이 주석에서 with 및 catch 문을 지적한 것을 기반으로 게시물을 편집하고 더 추가했습니다. 모두가 함께하고 catch 문은 각각의 블록으로 변수를 소개하고 그 블록 범위입니다. 이러한 변수는 전달된 개체의 속성에 별칭이 지정됩니다.

 //chrome (v8) var a = { 'test1':'test1val' } test1 // error not defined with (a) { var test1 = 'replaced' } test1 // undefined a // a.test1 = 'replaced'

편집: 명확한 예:

test1은 with 블록으로 범위가 지정되지만 .test1로 별칭이 지정됩니다. 'Var test1'은 상위 어휘 컨텍스트(함수 또는 전역)에 새로운 변수 test1을 생성합니다.

좋아! 'with'를 사용하는 데 주의하십시오. 변수가 이미 함수에 정의되어 있는 경우 var가 noop인 것처럼 객체에서 가져온 이름과 관련하여도 noop입니다! 이미 정의되고 있는 이름에 대해 조금만 주의를 기울이면 훨씬 더 안전하게 만들 수 있습니다. 나는 개인적으로 이것 때문에 와 함께 사용하지 않을 것입니다.


Gerard ONeill

JavaScript를 처음 접하는 많은 사람들이 언어에서 기본적으로 상속이 가능하고 함수 범위가 유일한 범위라는 사실을 이해하는 데 어려움을 겪고 있음을 발견했습니다. 작년 말에 작성한 JSPretty라는 미화에 대한 확장 기능을 제공했습니다. 기능 색상은 코드에서 기능 범위를 지정하고 항상 해당 범위에서 선언된 모든 변수에 색상을 연결합니다. 한 범위의 색상을 가진 변수가 다른 범위에서 사용될 때 폐쇄가 시각적으로 시연됩니다.

다음 위치에서 기능을 사용해 보세요.

데모 보기:

코드 보기:

현재 이 기능은 16개의 중첩된 함수에 대한 지원을 제공하지만 현재 전역 변수에 색상을 지정하지 않습니다.


austincheney

JavaScript에는 두 가지 유형의 범위만 있습니다.

  1. 전역 범위 : 전역은 창 수준 범위에 불과합니다. 여기에서 응용 프로그램 전체에 존재하는 변수입니다.
  2. 기능 범위 var 키워드로 함수 내에서 선언된 변수는 기능 범위를 가집니다.

함수가 호출될 때마다 JavaScript에서 변수가 뒤따르는 변수 범위 개체가 생성되고 범위 체인에 포함됩니다.

 a = "global"; function outer(){ b = "local"; console.log(a+b); //"globallocal" } outer();

범위 체인 -->

  1. 윈도우 레벨 - 및 a outer 함수 범위 체인의 최고 레벨에있다.
  2. 외부 함수가 내부에 b variable scope object (및 범위 체인에 포함됨)를 호출할 때.

이제 변수 a 필요할 때 가장 가까운 변수 범위를 먼저 검색하고 변수가 없으면 변수 범위 체인의 다음 개체로 이동합니다. 이 경우에는 창 수준입니다.


Anshul

코드를 실행합니다. 이것이 범위 지정에 대한 아이디어를 제공하기를 바랍니다.

 Name = 'global data'; document.Name = 'current document data'; (function(window,document){ var Name = 'local data'; var myObj = { Name: 'object data', f: function(){ alert(this.Name); } }; myObj.newFun = function(){ alert(this.Name); } function testFun(){ alert("Window Scope : " + window.Name + "\nLocal Scope : " + Name + "\nObject Scope : " + this.Name + "\nCurrent document Scope : " + document.Name ); } testFun.call(myObj); })(window,document);

Yeasin Abedin

글로벌 범위:

글로벌 변수는 글로벌 스타와 정확히 같습니다(Jackie Chan, Nelson Mandela). 애플리케이션의 어느 부분에서나 액세스할 수 있습니다(값 가져오기 또는 설정). 글로벌 기능은 글로벌 이벤트(새해, 크리스마스)와 같습니다. 애플리케이션의 모든 부분에서 실행(호출)할 수 있습니다.

 //global variable var a = 2; //global function function b(){ console.log(a); //access global variable }

지역 범위:

미국에 계시다면 악명 높은 유명인인 Kim Kardashian을 아실 것입니다. 그러나 미국 이외의 사람들은 그녀를 알아보지 못할 것입니다. 그녀는 그녀의 영역에 묶인 지역 스타입니다.

지역 변수는 지역 별과 같습니다. 범위 내에서만 액세스(값 가져오기 또는 설정)할 수 있습니다. 로컬 함수는 로컬 이벤트와 같습니다. 해당 범위 내에서만 실행(축하)할 수 있습니다. 범위 외부에서 액세스하려는 경우 참조 오류가 발생합니다.

 function b(){ var d = 21; //local variable console.log(d); function dog(){ console.log(a); } dog(); //execute local function } console.log(d); //ReferenceError: dddddd is not defined

범위에 대한 심층적인 이해를 위해 이 문서를 확인하십시오.


Jhankar Mahbub

다른 답변에 추가하기 위해 범위는 선언된 모든 식별자(변수)의 조회 목록이며 현재 실행 중인 코드에서 이러한 식별자에 액세스할 수 있는 방법에 대한 엄격한 규칙을 적용합니다. 이 조회는 LHS(왼쪽) 참조인 변수에 할당하기 위한 것일 수도 있고 RHS(오른쪽) 참조인 해당 값을 검색하기 위한 것일 수도 있습니다. 이러한 조회는 JavaScript 엔진이 코드를 컴파일하고 실행할 때 내부적으로 수행하는 작업입니다.

따라서 이러한 관점에서 Kyle Simpson의 Scopes and Closures ebook에서 찾은 그림이 도움이 될 것이라고 생각합니다.

영상

그의 전자책에서 인용:

건물은 프로그램의 중첩 범위 규칙 집합을 나타냅니다. 건물의 1층은 어디에 있든 현재 실행 중인 범위를 나타냅니다. 건물의 최상위 레벨은 글로벌 범위입니다. 현재 층을 보고 LHS 및 RHS 참조를 해결하고, 찾지 못하면 엘리베이터를 타고 다음 층으로 이동하고, 거기에서 찾은 다음 다음 층을 찾는 등의 방식으로 진행됩니다. 최상층(전역 범위)에 도달하면 원하는 것을 찾거나 찾지 못할 수 있습니다. 그러나 당신은 상관없이 중지해야합니다.

언급할 가치가 있는 한 가지 유의할 점은 "범위 조회는 첫 번째 일치 항목을 찾으면 중지됩니다."입니다.

"범위 수준"에 대한 이 아이디어는 중첩된 함수에서 조회되는 경우 새로 생성된 범위로 "이것"을 변경할 수 있는 이유를 설명합니다. 다음은 이러한 모든 세부 정보로 이동하는 링크입니다. 자바스크립트 범위에 대해 알고 싶은 모든 것


James Drinkard

JavaScript 범위에는 거의 두 가지 유형만 있습니다.

  • 각 var 선언의 범위는 가장 즉시 둘러싸는 함수와 연결됩니다.
  • var 선언을 위한 둘러싸는 함수가 없으면 전역 범위입니다.

따라서 함수 이외의 블록은 새 범위를 생성하지 않습니다. 이는 for 루프가 외부 범위 변수를 덮어쓰는 이유를 설명합니다.

 var i = 10, v = 10; for (var i = 0; i < 5; i++) { var v = 5; } console.log(i, v); // output 5 5

대신 함수 사용:

 var i = 10, v = 10; $.each([0, 1, 2, 3, 4], function(i) { var v = 5; }); console.log(i,v); // output 10 10

첫 번째 예에서는 블록 범위가 없었기 때문에 처음에 선언된 변수를 덮어썼습니다. 두 번째 예에서는 함수로 인해 새로운 범위가 생겨서 초기에 선언된 변수가 SHADOWED였으며 덮어쓰지 않았습니다.

다음을 제외하고 JavaScript 범위 지정과 관련하여 알아야 할 거의 모든 것입니다.

따라서 JavaScript 범위 지정이 항상 직관적이지는 않지만 실제로는 매우 간단하다는 것을 알 수 있습니다. 알아야 할 몇 가지 사항:

  • var 선언은 범위의 맨 위로 호이스트됩니다. 이것은 var 선언이 어디에서 발생하든 상관없이 컴파일러에게 var 자체가 맨 위에서 발생하는 것과 같다는 것을 의미합니다.
  • 동일한 범위 내에서 여러 var 선언이 결합됩니다.

따라서 이 코드는 다음과 같습니다.

 var i = 1; function abc() { i = 2; var i = 3; } console.log(i); // outputs 1

는 다음과 같습니다.

 var i = 1; function abc() { var i; // var declaration moved to the top of the scope i = 2; i = 3; // the assignment stays where it is } console.log(i);

이것은 직관적이지 않은 것처럼 보일 수 있지만 명령형 언어 디자이너의 관점에서는 의미가 있습니다.


jackbean818

현대 Js, ES6+, ' const ' 및 ' let '

대부분의 다른 주요 언어와 마찬가지로 생성하는 모든 변수에 대해 블록 범위를 사용해야 합니다. var더 이상 사용되지 않습니다 . 이렇게 하면 코드가 더 안전하고 유지 관리가 쉬워집니다.

const 는 95%의 경우에 사용해야 합니다. 변수 참조 를 변경할 수 없도록 합니다. 배열, 개체 및 DOM 노드 속성은 변경될 수 있으며 아마도 const 여야 합니다.

let 은 재할당될 것으로 예상되는 모든 변수에 사용해야 합니다. 여기에는 for 루프 내도 포함됩니다. 초기화를 넘어 값을 변경하는 경우 let 사용하십시오.

블록 범위는 변수가 선언된 대괄호 내에서만 사용할 수 있음을 의미합니다. 이는 범위 내에서 생성된 익명 함수를 포함하여 내부 범위로 확장됩니다.


Gibolt

인라인 핸들러

프론트 엔드 코더가 자주 실행하는 아직 설명되지 않은 매우 일반적인 문제는 HTML의 인라인 이벤트 핸들러에 표시되는 범위입니다.

 <button onclick="foo()"></button>

on* 속성이 참조할 수 있는 변수의 범위는 다음 중 하나 여야 합니다.

  • 전역(작업 인라인 처리기는 거의 항상 전역 변수를 참조함)
  • 문서의 속성 (예 querySelector 를 가리 독립 변수로 document.querySelector ; 드문)
  • 핸들러가 첨부된 요소의 속성 (위와 같이, 드물게)

그렇지 않으면 핸들러가 호출될 때 ReferenceError가 발생합니다. 따라서 예를 들어 인라인 핸들러가 window.onload 또는 $(function() { 내부 에 정의된 함수를 참조하는 경우 인라인 핸들러는 전역 범위의 변수만 참조할 수 있고 함수는 참조하지 않기 때문에 참조가 실패합니다. 글로벌:

 window.addEventListener('DOMContentLoaded', () => { function foo() { console.log('foo running'); } });
 <button onclick="foo()">click</button>

document 속성과 핸들러가 연결된 요소의 속성은 인라인 핸들러 내에서 독립형 변수로 참조될 수도 있습니다. 인라인 핸들러는 두 개의 with 블록 (하나는 document , 하나는 요소용) 내부에서 호출되기 때문입니다. 이러한 핸들러 내부의 변수 범위 체인은 매우 직관적이지 않으며 작동하는 이벤트 핸들러는 아마도 전역 함수를 요구할 것입니다(그리고 불필요한 전역 오염 은 아마도 피해야 합니다 ).

인라인 처리기 내부의 범위 체인이 너무 이상 하고 인라인 처리기가 작동하려면 전역 오염이 필요하고 인라인 처리기가 인수를 전달할 때 때때로 추악한 문자열 이스케이프가 필요하기 때문에 피하는 것이 더 쉬울 것입니다. 대신 HTML 마크업이 아닌 addEventListener 와 같은)를 사용하여 이벤트 핸들러를 연결하십시오.

 function foo() { console.log('foo running'); } document.querySelector('.my-button').addEventListener('click', foo);
 <button class="my-button">click</button>

모듈( <script type="module"> )

다른 점 <script> 태그와 달리 ES6 모듈 내부의 코드는 자체 비공개 범위에서 실행됩니다. <script> 태그 상단에 정의된 변수는 전역 변수이므로 다음과 같이 <script> 태그에서 참조할 수 있습니다.

 <script> const foo = 'foo'; </script> <script> console.log(foo); </script>

그러나 ES6 모듈의 최상위 레벨은 전역 적이지 않습니다. ES6 모듈의 맨 위에 선언된 변수는 변수가 명시적으로 export 지거나 전역 객체의 속성에 할당되지 않는 한 해당 모듈 내부에서만 볼 수 있습니다.

 <script type="module"> const foo = 'foo'; </script> <script> // Can't access foo here, because the other script is a module console.log(typeof foo); </script>

ES6 모듈의 최상위 레벨은 일반 <script> 의 최상위 IIFE 내부와 유사합니다. 모듈은 전역 변수를 참조할 수 있으며 모듈이 명시적으로 설계되지 않는 한 모듈 내부의 어떤 것도 참조할 수 없습니다.


CertainPerformance

이 흥미로운 예를 시도해 보십시오. 아래 예에서 a가 0으로 초기화된 숫자인 경우 0과 1이 차례로 표시됩니다. a가 객체이고 javascript가 f1에 복사본이 아닌 a의 포인터를 전달한다는 점을 제외하고. 결과는 두 번 모두 동일한 경고를 받는 것입니다.

 var a = new Date(); function f1(b) { b.setDate(b.getDate()+1); alert(b.getDate()); } f1(a); alert(a.getDate());

Mig82

JS에는 함수 범위만 있습니다. 차단 범위가 아닙니다! 끌어올리고 있는 것도 볼 수 있습니다.

 var global_variable = "global_variable"; var hoisting_variable = "global_hoist"; // Global variables printed console.log("global_scope: - global_variable: " + global_variable); console.log("global_scope: - hoisting_variable: " + hoisting_variable); if (true) { // The variable block will be global, on true condition. var block = "block"; } console.log("global_scope: - block: " + block); function local_function() { var local_variable = "local_variable"; console.log("local_scope: - local_variable: " + local_variable); console.log("local_scope: - global_variable: " + global_variable); console.log("local_scope: - block: " + block); // The hoisting_variable is undefined at the moment. console.log("local_scope: - hoisting_variable: " + hoisting_variable); var hoisting_variable = "local_hoist"; // The hoisting_variable is now set as a local one. console.log("local_scope: - hoisting_variable: " + hoisting_variable); } local_function(); // No variable in a separate function is visible into the global scope. console.log("global_scope: - local_variable: " + local_variable);

koredalin

내 이해는 세 가지 범위가 있다는 것입니다. 전역 범위, 전 세계적으로 사용 가능; 블록에 관계없이 전체 기능에서 사용할 수 있는 로컬 범위; 사용된 블록, 명령문 또는 표현식에만 사용할 수 있는 블록 범위. 전역 및 지역 범위는 함수 내 또는 외부에서 키워드 'var'로 표시되고 블록 범위는 키워드 'let'으로 표시됩니다.

전역 및 지역 범위만 있다고 믿는 사람들을 위해 Mozilla가 JS에서 블록 범위의 뉘앙스를 설명하는 전체 페이지를 갖는 이유를 설명하십시오.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let


mrmaclean89

JavaScript에는 두 가지 유형의 범위가 있습니다.

  • 로컬 범위
  • 글로벌 범위

아래 함수에는 지역 범위 변수 carName 있습니다. 그리고 이 변수는 함수 외부에서 접근할 수 없습니다.

 function myFunction() { var carName = "Volvo"; alert(carName); // code here can use carName }

아래 클래스에는 전역 범위 변수 carName 있습니다. 그리고 이 변수는 클래스의 모든 곳에서 액세스할 수 있습니다.

 class { var carName = " Volvo"; // code here can use carName function myFunction() { alert(carName); // code here can use carName } }

Abdur Rahman

나는 허용 된 답변을 정말 좋아하지만 이것을 추가하고 싶습니다.

범위는 선언된 모든 식별자(변수)의 조회 목록을 수집 및 유지 관리하고 현재 실행 중인 코드에서 이러한 식별자에 액세스할 수 있는 방법에 대한 엄격한 규칙을 적용합니다.

범위는 식별자 이름으로 변수를 찾기 위한 일련의 규칙입니다.

  • 직접 범위에서 변수를 찾을 수 없는 경우 엔진은 다음 외부 포함 범위를 참조하여 찾거나 가장 바깥쪽(일명 전역) 범위에 도달할 때까지 계속합니다.
  • 변수(식별자)를 조회할 수 있는 위치와 방법을 결정하는 규칙 집합입니다. 이 조회는 LHS(왼쪽) 참조인 변수에 할당하기 위한 것일 수도 있고 RHS(오른쪽) 참조인 값을 검색하기 위한 것일 수도 있습니다. .
  • LHS 참조는 할당 작업의 결과입니다. 범위 관련 할당은 = 연산자를 사용하거나 함수 매개변수에 인수를 전달(할당)하여 발생할 수 있습니다.
  • JavaScript 엔진은 실행되기 전에 먼저 코드를 컴파일하고, 그렇게 하는 동안 var a = 2와 같은 명령문을 분할합니다. 두 단계로 나뉩니다. 먼저 var a를 사용하여 해당 범위에서 선언합니다. 이것은 코드 실행 전에 처음에 수행됩니다. 2번째. 나중에 a = 2를 사용하여 변수(LHS 참조)를 찾고 발견되면 할당합니다.
  • LHS 및 RHS 참조 조회는 모두 현재 실행 중인 범위에서 시작하며 필요한 경우(즉, 그곳에서 찾고 있는 것을 찾지 못하는 경우) 중첩된 범위, 한 범위(바닥 ) 한 번에 식별자를 찾고 글로벌(최상층)에 도달하고 중지하고 찾거나 하지 않습니다. 충족되지 않은 RHS 참조로 인해 ReferenceError가 발생합니다. 충족되지 않은 LHS 참조는 해당 이름의 암시적으로 자동 생성된 전역(엄격 모드가 아닌 경우) 또는 ReferenceError(엄격 모드에 있는 경우)를 초래합니다.
  • 범위는 각각 컨테이너 또는 버킷 역할을 하는 일련의 "버블"로 구성되며, 여기서 식별자(변수, 함수)가 선언됩니다. 이 거품은 서로 깔끔하게 중첩되며 이 중첩은 작성자 시점에 정의됩니다.

Ahmed Khashaba

ES5 및 이전 버전:

Javascript의 변수는 초기에( ES6 이전) 사전적으로 함수 범위였습니다. 어휘 범위라는 용어는 코드를 '보고'하여 변수의 범위를 볼 수 있음을 의미합니다.

var 키워드로 선언된 모든 변수는 함수로 범위가 지정됩니다. 그러나 해당 함수 내에서 다른 함수가 선언된 경우 해당 함수는 외부 함수의 변수에 액세스할 수 있습니다. 이를 범위 체인 이라고 합니다. 다음과 같은 방식으로 작동합니다.

  1. 함수가 변수 값을 확인하려고 할 때 먼저 자체 범위를 찾습니다. 이것은 함수 본문, 즉 중괄호 {} 사이의 모든 것입니다(이 범위에 있는 다른 함수 내부의 변수 제외).
  2. 함수 본문 내에서 변수를 찾을 수 없으면 체인까지 올라가서 함수가 정의된 함수의 변수 범위를 찾습니다. 이것이 어휘 범위가 의미하는 바입니다. 코드에서 이 함수가 정의된 위치를 볼 수 있으므로 코드를 보는 것만으로 범위 체인을 결정할 수 있습니다.

예시:

 // global scope var foo = 'global'; var bar = 'global'; var foobar = 'global'; function outerFunc () { // outerFunc scope var foo = 'outerFunc'; var foobar = 'outerFunc'; innerFunc(); function innerFunc(){ // innerFunc scope var foo = 'innerFunc'; console.log(foo); console.log(bar); console.log(foobar); } } outerFunc();

foo , bar , foobar 를 콘솔에 기록하려고 할 때 일어나는 일은 다음과 같습니다:

  1. foo를 콘솔에 기록하려고 합니다. foo는 innerFunc 함수 내부에서 찾을 수 있습니다. 따라서 foo 값은 innerFunc 문자열로 해석됩니다.
  2. innerFunc 함수 내부에서 bar를 찾을 수 없습니다. 따라서 범위 체인 을 올라야 합니다. innerFunc 함수가 정의된 외부 함수를 살펴봅니다. 이것은 outerFunc 함수입니다. outerFunc 의 범위에서 'outerFunc' 문자열을 포함하는 변수 bar를 찾을 수 있습니다.
  3. foobar는 innerFunc에서 찾을 수 없습니다. . 따라서 범위 체인을 innerFunc 범위 로 올라가야 합니다. 여기에서도 찾을 수 없습니다. 우리는 전역 범위 (즉, 가장 바깥쪽 범위)로 또 다른 수준으로 올라갑니다. 여기에서 'global' 문자열을 포함하는 변수 foobar를 찾습니다. 범위 체인을 올라간 후 변수를 찾지 못한 경우 JS 엔진은 referenceError 를 발생 시킵니다.

ES6 (ES 2015) 이상:

어휘 범위와 범위 체인의 동일한 개념이 ES6 에도 여전히 적용됩니다. 그러나 변수를 선언하는 새로운 방법이 도입되었습니다. 다음이 있습니다.

  • let : 블록 범위 변수를 생성합니다.
  • const : 초기화해야 하고 재할당할 수 없는 블록 범위 변수를 생성합니다.

가장 큰 차이점 varlet / constvar 반면 함수 범위가 let / const 블록 범위가된다. 다음은 이를 설명하는 예입니다.

 let letVar = 'global'; var varVar = 'global'; function foo () { if (true) { // this variable declared with let is scoped to the if block, block scoped let letVar = 5; // this variable declared with let is scoped to the function block, function scoped var varVar = 10; } console.log(letVar); console.log(varVar); } foo();

let 으로 선언된 변수가 블록 범위이기 때문에 전역 값을 기록합니다. 그것들은 각각의 블록 외부에 존재하지 않으므로 if 블록 외부에서 변수에 액세스할 수 없습니다.


Willem van der Veen

EcmaScript5에는 주로 로컬 범위전역 범위의 두 가지 범위가 있지만 EcmaScript6에는 주로 지역 범위, 전역 범위 및 블록 범위 라는 새 범위의 세 가지 범위가 있습니다.

블록 범위의 예는 다음과 같습니다.

 for ( let i = 0; i < 10; i++) { statement1... statement2...// inside this scope we can access the value of i, if we want to access the value of i outside for loop it will give undefined. }

Vivek Mehta

ECMAScript 6은 let 및 const 키워드를 도입했습니다. 이러한 키워드는 var 키워드 대신 사용할 수 있습니다. var 키워드와 달리 let 및 const 키워드는 블록 문 내에서 지역 범위 선언을 지원합니다.

 var x = 10 let y = 10 const z = 10 { x = 20 let y = 20 const z = 20 { x = 30 // x is in the global scope because of the 'var' keyword let y = 30 // y is in the local scope because of the 'let' keyword const z = 30 // z is in the local scope because of the 'const' keyword console.log(x) // 30 console.log(y) // 30 console.log(z) // 30 } console.log(x) // 30 console.log(y) // 20 console.log(z) // 20 } console.log(x) // 30 console.log(y) // 10 console.log(z) // 10

Davaakhuu Erdenekhuu

 (function foo() { console.log(foo) })(); console.log(typeof foo); // undefined, because `foo` is scoped to its own expression //but, like this (function foo() { console.log('1:', foo) // function foo foo = 100 console.log('2:', foo) // function foo, is not 100, why? })()


ludy

JavaScript에는 두 가지 유형의 범위가 있습니다.

  1. 전역 범위 : 전역 범위에서 선언된 변수는 프로그램의 어느 곳에서나 매우 원활하게 사용할 수 있습니다. 예를 들어:

     var carName = " BMW"; // code here can use carName function myFunction() { // code here can use carName }
  2. 기능 범위 또는 로컬 범위 : 이 범위에서 선언된 변수는 자체 함수에서만 사용할 수 있습니다. 예를 들어:

     // code here can not use carName function myFunction() { var carName = "BMW"; // code here can use carName }

A. Randhawa

출처 : http:www.stackoverflow.com/questions/500431/what-is-the-scope-of-variables-in-javascript

반응형