자바 스크립트에서 변수의 범위는 무엇입니까? 함수 외부와 반대로 내부와 동일한 범위를 가지고 있습니까? 아니면 중요합니까? 또한 전역 적으로 정의 된 변수는 어디에 저장됩니까?
자바 스크립트에서 변수의 범위는 무엇입니까? 함수 외부와 반대로 내부와 동일한 범위를 가지고 있습니까? 아니면 중요합니까? 또한 전역 적으로 정의 된 변수는 어디에 저장됩니까?
답변:
JavaScript에는 어휘 (정적이라고도 함) 범위 지정 및 클로저가 있습니다. 즉, 소스 코드를 보면 식별자의 범위를 알 수 있습니다.
네 가지 범위는 다음과 같습니다.
전역 및 모듈 범위의 특수한 경우를 제외하고 변수는 var
(함수 범위), let
(블록 범위) 및 const
(블록 범위)를 사용하여 선언됩니다 . 대부분의 다른 형태의 식별자 선언은 엄격 모드에서 블록 범위를 갖습니다.
범위는 식별자가 유효한 코드베이스의 영역입니다.
어휘 환경은 식별자 이름과 관련된 값 사이의 매핑입니다.
범위는 어휘 환경의 연결된 중첩으로 구성되며, 중첩의 각 레벨은 상위 실행 컨텍스트의 어휘 환경에 해당합니다.
이러한 연결된 어휘 환경은 범위 "체인"을 형성합니다. 식별자 확인은이 체인을 따라 일치하는 식별자를 검색하는 프로세스입니다.
식별자 해상도는 한 방향으로 만 발생합니다 : 바깥 쪽. 이러한 방식으로 외부 어휘 환경은 내부 어휘 환경을 "볼"수 없습니다.
JavaScript 에서 식별자 의 범위 를 결정하는 데는 세 가지 관련 요소가 있습니다 .
식별자를 선언 할 수있는 몇 가지 방법 :
var
, let
및const
var
엄격하지 않은 모드에서는 누락 )import
진술eval
위치 식별자 중 일부를 선언 할 수 있습니다.
전역 컨텍스트에서 직접 선언 된 경우를 제외하고 사용하여 선언 된 식별자 에는 전역 범위에서 특성으로 추가되고 전역 var
범위가있는 함수 범위가 있습니다 . eval
기능에 사용하기위한 별도의 규칙이 있습니다.
식별자를 사용하여 선언 let
과 const
블록 범위를 가지고 는 그들이 글로벌 범위를 가지고있는 경우에 국제적인 맥락에서 직접 선언 할 때 그렇다.
참고 : let
, const
및 var
모든 게양된다 . 이는 논리적 정의 위치가 둘러싸는 범위 (블록 또는 기능)의 최상위임을 의미합니다. 그러나 변수는 useing 선언 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
간접적으로 사용되는 전역 객체 건물.
다음은 이름 때문에 ReferenceError가 발생합니다 x
, y
그리고 z
함수의 의미의 외부가 없습니다 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
및 z
에 대해서는 ReferenceError를 발생 시키지 않습니다. 제어 구조의 시체를 정의 블록 좋아 , 와 유사하게 동작합니다.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
루프에서 사용하여 선언 된 변수를 닫을 때주의해야합니다 . 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
캐치 블록 매개 변수는 캐치 블록 본체에 적용됩니다.
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에서 모든 function-object에는 숨겨진 컨텍스트 가 있으며 실행 컨텍스트 (스택 프레임) [[Environment]]
의 어휘 환경 에 대한 참조 입니다.
함수를 호출하면 숨겨진 [[Call]]
메소드가 호출됩니다. 이 메소드는 새 실행 컨텍스트를 작성하고 새 실행 컨텍스트와 함수 오브젝트의 어휘 환경 사이에 링크를 설정합니다. [[Environment]]
함수 객체 의 값을 새 실행 컨텍스트의 어휘 환경에 있는 외부 참조 필드에 복사하여이를 수행합니다.
새로운 실행 컨텍스트와 함수 객체의 어휘 환경 사이의이 링크를 클로저 라고합니다 .
따라서 JavaScript에서 범위는 외부 참조에 의해 "체인"으로 함께 연결된 어휘 환경을 통해 구현됩니다. 이 어휘 환경 체인을 스코프 체인이라고하며, 식별자 확인 은 일치하는 식별자를 찾기 위해 체인 을 검색하여 발생합니다 .
자세한 내용을 알아보십시오 .
Javascript는 범위 체인을 사용하여 지정된 함수의 범위를 설정합니다. 일반적으로 하나의 전역 범위가 있으며 정의 된 각 함수에는 자체 중첩 범위가 있습니다. 다른 함수 내에 정의 된 모든 함수에는 외부 함수에 연결된 로컬 범위가 있습니다. 항상 범위를 정의하는 소스의 위치입니다.
스코프 체인의 요소는 기본적으로 상위 범위에 대한 포인터가있는 맵입니다.
변수를 해결할 때 javascript는 가장 안쪽 범위에서 시작하여 바깥쪽으로 검색합니다.
전역 적으로 선언 된 변수에는 전역 범위가 있습니다. 함수 내에서 선언 된 변수는 해당 함수로 범위가 지정되고 동일한 이름의 전역 변수를 음영 처리합니다.
(나는 확실히 실제 자바 스크립트 프로그래머는 다른 답변에서 지적 할 수있을 것으로 많은 미묘한이있다하고 있습니다. 특히 내가 건너 온에서 이 페이지 정확히 무엇에 대해 this
언제든지 의미합니다. 희망은 이 더 소개 링크가 당신이 생각 시작할 수 있도록 충분하다 .)
일반적으로 JavaScript는 실제로 두 가지 유형의 범위 만 있습니다.
차이점을 설명하는 다른 많은 답변이 이미 있기 때문에 이에 대해 자세히 설명하지 않습니다.
가장 최근의 자바 스크립트 사양은 이제 세 번째 범위를 허용 :
전통적으로 다음과 같이 변수를 만듭니다.
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 코드를 작성하고 traceur 쉘 스크립트 또는 Babel 과 같은 노드 기반 변환기를 사용하는 경우 let
명령문을 안전하게 사용할 수 있습니다 . 그리고 브라우저는 변환 된 코드에 대해서만 알기 때문에 성능 단점이 제한되어야합니다.
클라이언트 측 JavaScript 코드를 작성 중이고 트랜스 파일러를 사용하지 않는 경우 브라우저 지원을 고려해야합니다.
이들은 전혀 지원하지 않는 일부 브라우저입니다 let
.
let
이 답변을 읽을 당시의 진술을 지원하는 브라우저에 대한 최신 개요는 이 Can I Use
페이지를 참조 하십시오 .
(*) JavaScript 변수가 들어 있기 때문에 전역 및 기능적으로 범위가 지정된 변수를 선언하기 전에 초기화하고 사용할 수 있습니다 . 이것은 선언이 항상 범위의 맨 위에 있다는 것을 의미합니다.
예를 들면 다음과 같습니다.
<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>
클로저를 조사하고 클로저를 사용하여 비공개 회원 을 만드는 방법을 조사해야합니다 .
내가 이해하는 열쇠는 Javascript가 기능 수준 범위 지정보다 일반적인 C 블록 범위 지정이라는 것입니다.
"Javascript 1.7"(Mozilla의 Javascript 확장)에서 다음 과 같이 let
statement -scope 변수를 선언 할 수 있습니다 .
var a = 4;
let (a = 3) {
alert(a); // 3
}
alert(a); // 4
let
.
Brendan Eich 가 처음 디자인했을 때 JavaScript 범위 지정 아이디어 는 HyperCard 스크립팅 언어 인 HyperTalk 에서 나왔습니다 .
이 언어에서는 디스플레이가 인덱스 카드 스택과 유사하게 수행되었습니다. 배경이라고하는 마스터 카드가있었습니다. 투명하고 맨 아래 카드로 볼 수 있습니다. 이 기본 카드의 모든 내용은 그 위에 놓인 카드와 공유되었습니다. 상단에 배치 된 각 카드에는 이전 카드보다 우선하는 고유 한 내용이 있지만 원하는 경우 여전히 이전 카드에 액세스 할 수있었습니다.
이것이 바로 JavaScript 범위 시스템이 설계된 방식입니다. 이름이 다릅니다. JavaScript의 카드는 Execution Contexts ECMA라고 합니다. 이러한 맥락 각각에는 세 가지 주요 부분이 있습니다. 가변 환경, 어휘 환경 및이 바인딩 카드 참조로 돌아가서 어휘 환경에는 이전 카드의 모든 내용이 스택 아래에 포함됩니다. 현재 컨텍스트는 스택 맨 위에 있으며 여기에 선언 된 모든 컨텐츠는 가변 환경에 저장됩니다. 이름 충돌의 경우 변수 환경이 우선합니다.
이 바인딩은 포함하는 객체를 가리 킵니다. 포함 개체가 생성 된 선언 된 함수 window
나 생성자 함수 와 같이 포함 개체를 변경하지 않고 범위 나 실행 컨텍스트가 변경되는 경우가 있습니다 .
이러한 실행 컨텍스트는 제어가 전송 될 때마다 작성됩니다. 코드 실행이 시작되면 제어가 전송되며 이는 주로 함수 실행에서 수행됩니다.
이것이 기술적 인 설명입니다. 실제로는 JavaScript에서이를 기억하는 것이 중요합니다
이 페이지의 이전 예제 중 하나 (5. "Closure")에이를 적용하면 실행 컨텍스트 스택을 따를 수 있습니다. 이 예에서는 스택에 세 가지 컨텍스트가 있습니다. 외부 컨텍스트, var six에 의해 호출 된 즉시 호출 된 함수의 컨텍스트 및 var six의 즉시 호출 된 함수 내에서 리턴 된 함수의 컨텍스트에 의해 정의됩니다.
i ) 외부 상황. 변수 환경 a = 1
ii ) IIFE 컨텍스트, 어휘 환경 a = 1이지만 스택 환경에서 우선 순위가 높은 a = 6 변수 환경
iii ) 리턴 된 함수 컨텍스트, 어휘 a = 6의 환경이며 호출 될 때 경고에서 참조되는 값입니다.
1) 전역 범위, 기능 범위 및 with 및 catch 범위가 있습니다. 변수에 대해 일반적으로 '블록'레벨 범위는 없습니다. with 및 catch 문은 블록에 이름을 추가합니다.
2) 범위는 전역 범위까지 모든 기능에 의해 중첩됩니다.
3) 프로토 타입 체인을 통해 속성이 해결됩니다. with 문은 객체 속성 이름을 with 블록으로 정의 된 어휘 범위로 가져옵니다.
편집 : ECMAAScript 6 (Harmony)은 let을 지원하도록 지정되어 있으며 크롬은 'harmony'플래그를 허용하므로 아마도 지원합니다.
블록 레벨 범위 지정을 지원하지만 키워드를 사용하여이를 수행해야합니다.
편집 : 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 블록이지만 a.test1의 별칭입니다. 'Var test1'은 어휘 컨텍스트 (함수 또는 전역)에 새로운 변수 test1을 작성합니다.
이케! 변수가 이미 함수에 정의되어 있다면 var는 noop 인 것처럼 'with'를 사용하는 것에주의하십시오. 객체에서 가져온 이름과 관련하여 noop이기도합니다! 이미 정의 된 이름에 약간의 머리글이 있으면 훨씬 더 안전합니다. 이 때문에 개인적으로는 절대 사용하지 않습니다.
with
문 입니다 블록 범위 지정의 형태는하지만 catch
절은 훨씬 더 일반적인 형태 (재미있는 사실, V8의 구현입니다 catch
A를 with
) - 자바 스크립트 자체 (즉, 기능, 글로벌, 시도 / 잡기에 거의 블록 범위 지정의 유일한 형태이다 호스트 환경과 브라우저의 인라인 이벤트 및 NodeJS의 vm 모듈과 같은 범위 지정 개념이 다릅니다.
JavaScript를 처음 접하는 많은 사람들은 기본적으로 언어에서 상속이 가능하며 함수 범위가 유일한 범위라는 것을 이해하는 데 어려움을 겪었습니다. 작년 말에 JSPretty라고 썼던 미용사에 대한 확장을 제공했습니다. 피처 색상은 코드에서 기능 범위이며 항상 해당 범위에서 선언 된 모든 변수에 색상을 연결합니다. 한 범위의 색상을 가진 변수가 다른 범위에서 사용될 때 클로저가 시각적으로 표시됩니다.
다음에서 기능을 사용해보십시오.
다음에서 데모를보십시오 :
다음에서 코드를보십시오.
현재이 기능은 깊이가 16 인 중첩 함수를 지원하지만 전역 변수에 색상을 지정하지는 않습니다.
JavaScript에는 두 가지 유형의 범위 만 있습니다.
var
키워드를 사용 하여 함수 내에 선언 된 변수 에는 기능 범위가 있습니다.함수가 호출 될 때마다 변수 범위 개체가 만들어지고 범위 체인에 포함되며 그 뒤에 JavaScript의 변수가옵니다.
a = "global";
function outer(){
b = "local";
console.log(a+b); //"globallocal"
}
outer();
스코프 체인->
a
및 outer
기능은 범위 체인에서 최상위 수준에 있습니다.variable scope object
(및 스코프 체인에 포함)에 변수가 추가 된 b
경우.이제 변수가 a
필요할 때 가장 가까운 변수 범위를 검색하고 변수가 없으면 변수 범위 체인의 다음 객체로 이동합니다.이 경우 창 수준입니다.
다른 답변에 추가하기 위해 scope는 선언 된 모든 식별자 (변수)의 조회 목록이며 현재 실행중인 코드에 액세스 할 수있는 방법에 대한 엄격한 규칙을 시행합니다. 이 조회는 LHS (왼쪽) 참조 인 변수에 할당하기위한 것이거나 RHS (오른쪽) 참조 인 값을 검색하기위한 것일 수 있습니다. 이러한 조회는 JavaScript 엔진이 코드를 컴파일하고 실행할 때 내부적으로 수행하는 작업입니다.
이 관점에서, 그림이 Kyle Simpson의 Scopes and Closures ebook에서 찾은 데 도움이 될 것이라고 생각합니다.
그의 전자 책에서 인용 :
건물은 프로그램의 중첩 범위 규칙 세트를 나타냅니다. 건물의 1 층은 어디에 있든지 현재 실행중인 범위를 나타냅니다. 건물의 최상위 수준은 글로벌 범위입니다. 현재 층을 살펴보고 LHS 및 RHS 참조를 해결하고, 찾을 수없는 경우 엘리베이터를 다음 층으로 가져 가서 다음 층을 찾은 후 다음 등을 수행합니다. 최상층에 도달하면 (전세계 범위) 원하는 것을 찾거나 찾지 않습니다. 그러나 당신은 관계없이 멈춰야합니다.
주목할만한 한 가지 사항은 "첫 번째 일치 항목을 찾으면 스코프 조회가 중지됩니다"입니다.
"범위 수준"에 대한이 개념은 중첩 함수에서 조회되는 경우 "이"가 새로 작성된 범위로 변경 될 수있는 이유를 설명합니다. 여기에 모든 세부 사항으로 연결되는 링크가 있습니다 .Javascript 범위에 대해 알고 싶은 모든 것
코드를 실행하십시오. 이것이 범위 지정에 대한 아이디어를 줄 수 있기를 바랍니다.
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);
글로벌 변수는 글로벌 스타와 정확히 같습니다 (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
ALMOST에는 두 가지 유형의 JavaScript 범위 만 있습니다.
따라서 함수 이외의 블록은 새로운 범위를 만들지 않습니다. 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 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);
이것은 직관적이지 않은 것처럼 보일 수도 있지만 명령형 언어 디자이너의 관점에서 의미가 있습니다.
const
'및 ' let
'대부분의 다른 주요 언어와 마찬가지로 작성하는 모든 변수에 대해 블록 범위 지정을 사용해야합니다. var
이다 쓸모 . 이를 통해 코드를보다 안전하고 유지 관리 할 수 있습니다.
const
95 %의 경우에 사용해야합니다 . 변수 참조 를 변경할 수 없도록 만듭니다 . 배열, 객체 및 DOM 노드 속성은 변경 될 수 있으며 변경 될 수 있습니다 const
.
let
재 할당 될 것으로 예상되는 모든 변수에 사용해야합니다. 여기에는 for 루프가 포함됩니다. 초기화 이상으로 값을 변경 한 경우을 사용하십시오 let
.
블록 범위는 변수가 선언 된 괄호 내에서만 변수를 사용할 수 있음을 의미합니다. 이는 범위 내에서 생성 된 익명 함수를 포함하여 내부 범위로 확장됩니다.
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);
내 이해는 3 가지 범위가 있다는 것입니다 : 글로벌 범위, 전 세계적으로 사용 가능; 블록에 관계없이 전체 기능에 사용 가능한 로컬 범위; 그리고 블록 범위는 블록, 명령문 또는 블록이 사용 된 표현식에서만 사용 가능합니다. 전역 및 로컬 범위는 함수 내에서 또는 외부에서 키워드 'var'로 표시되며 블록 범위는 키워드 'let'으로 표시됩니다.
글로벌 및 로컬 범위 만 있다고 생각하는 사람들을 위해 Mozilla가 JS에서 블록 범위의 뉘앙스를 설명하는 전체 페이지를 갖는 이유를 설명하십시오.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
프론트 엔드 코더가 자주 발생하는 매우 일반적인 문제는 HTML에서 인라인 이벤트 핸들러에 표시되는 범위입니다.
<button onclick="foo()"></button>
on*
속성이 참조 할 수 있는 변수의 범위는 다음 중 하나 여야 합니다.
querySelector
독립형 변수는 document.querySelector
; 희귀)그렇지 않으면 핸들러가 호출 될 때 ReferenceError가 발생합니다. 예를 들어 인라인 핸들러가 or 안에 정의 된 함수를 참조하는 경우 인라인 핸들러는 전역 범위의 변수 만 참조 할 수 있고 함수는 전역이 아니므로 참조가 실패합니다.window.onload
$(function() {
의 속성 document
과 인라인 핸들러가 핸들러가 호출되기 때문에 또한 인라인 처리기 내부 독립 변수로 참조 될 수있는 부착 된 소자의 특성을 내부에 두개의 with
블록 은 하나 document
의 요소를 하나. 이러한 핸들러 내부 변수의 범위 체인은 매우 직관적 및 작동 이벤트 핸들러 것이다 아마도 글로벌하려고 한 기능을 요구 (글로벌 불필요한 오염 아마 피해야한다 ).
인라인 핸들러 내부의 스코프 체인은 너무 이상 하고 인라인 핸들러가 작동하려면 전역 오염이 필요하고 인라인 핸들러는 인수를 전달할 때 추악한 문자열 이스케이프가 필요하기 때문에 피하는 것이 더 쉽습니다. 대신 addEventListener
HTML 마크 업이 아닌 Javascript를 사용하여 이벤트 핸들러를 연결하십시오 .
다른 참고로 <script>
최상위 수준에서 실행되는 일반 태그 와 달리 ES6 모듈 내부의 코드는 자체 개인 범위에서 실행됩니다. 일반 <script>
태그 상단에 정의 된 변수 는 전역이므로 다음 <script>
과 같이 다른 태그 에서 참조 할 수 있습니다 .
그러나 ES6 모듈의 최상위 수준은 전 세계 가 아닙니다 . ES6 모듈 상단에 선언 된 변수는 변수가 명시 적으로 export
지정되거나 전역 객체의 속성에 할당되지 않은 경우 해당 모듈 내에서만 볼 수 있습니다 .
ES6 모듈의 최상위 레벨은 정상에서 최상위 레벨의 IIFE 내부와 유사합니다 <script>
. 모듈은 전역 변수를 참조 할 수 있으며, 모듈이 명시 적으로 설계되지 않은 경우 모듈 내부의 어떤 것도 참조 할 수 없습니다.
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
}
}
ES5
이전 :Javascript의 변수는 초기에 ES6
사전 기능 범위로 사용되었습니다. 어휘 범위라는 용어는 코드를 '보고'변수의 범위를 볼 수 있음을 의미합니다.
var
키워드로 선언 된 모든 변수의 범위는 함수입니다. 그러나 다른 함수가 해당 함수 내에 선언되면 해당 함수는 외부 함수의 변수에 액세스 할 수 있습니다. 이것을 스코프 체인 이라고합니다 . 다음과 같은 방식으로 작동합니다.
// 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
콘솔에 다음과 같다 :
innerFunc
자체 에서 찾을 수 있습니다 . 따라서 foo 값은 문자열로 확인됩니다 innerFunc
.innerFunc
자체 안에서 bar를 찾을 수 없습니다 . 따라서 스코프 체인 을 올라 가야합니다 . 먼저 함수 innerFunc
가 정의 된 외부 함수를 살펴 봅니다 . 이것은 기능 outerFunc
입니다. 범위 내 outerFunc
에서 문자열 'outerFunc'를 보유하는 변수 막대를 찾을 수 있습니다.ES6
(ES 2015) 이상 :어휘 범위와 범위 체인의 동일한 개념이 여전히 적용됩니다 ES6
. 그러나 변수를 선언하는 새로운 방법이 도입되었습니다. 다음이 있습니다 :
let
: 블록 범위 변수를 작성합니다const
: 초기화해야하고 재 할당 할 수없는 블록 범위 변수를 작성합니다.가장 큰 차이점 var
및 let
/ const
즉 var
함수 인 반면, 범위 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();
위의 예에서 letVar는로 선언 된 변수 let
가 블록 범위 이기 때문에 전역 값을 기록합니다 . 그것들은 각각의 블록 외부에 존재하지 않으므로 변수는 if 블록 외부에 액세스 할 수 없습니다.
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.
}
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
나는 받아 들인 대답을 정말로 좋아하지만 이것을 추가하고 싶다 :
Scope는 선언 된 모든 식별자 (변수)의 조회 목록을 수집하고 유지 관리하며 현재 실행중인 코드에 액세스 할 수있는 방법에 대한 엄격한 규칙을 적용합니다.
범위는 식별자 이름으로 변수를 조회하기위한 규칙 세트입니다.
JavaScript에는 두 가지 유형의 범위가 있습니다.
글로벌 스코프 : 글로벌 스코프에 공지 된 변수는 프로그램의 어느 곳에서나 매우 부드럽게 사용될 수 있습니다. 예를 들면 다음과 같습니다.
var carName = " BMW";
// code here can use carName
function myFunction() {
// code here can use carName
}
기능 범위 또는 로컬 범위 :이 범위에서 선언 된 변수는 자체 기능에서만 사용할 수 있습니다. 예를 들면 다음과 같습니다.
// code here can not use carName
function myFunction() {
var carName = "BMW";
// code here can use carName
}