자바 스크립트 함수 범위 지정 및 호이 스팅
방금 Ben Cherry의 JavaScript Scoping and Hoisting에 대한 훌륭한 기사를 읽었습니다 .
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);
위의 코드를 사용하면 브라우저는 "1"을 경고합니다.
왜 "1"을 반환하는지 잘 모르겠습니다. 그가 말한 것 중 일부는 다음과 같이 떠 오릅니다. 모든 함수 선언이 맨 위로 올라갑니다. 함수를 사용하여 변수의 범위를 지정할 수 있습니다. 여전히 나를 위해 클릭하지 않습니다.
기능 호이 스팅은 기능이 범위의 맨 위로 이동하는 것을 의미합니다. 그건,
function b() {
a = 10;
return;
function a() {}
}
interpeter에 의해 이것으로 다시 작성됩니다
function b() {
function a() {}
a = 10;
return;
}
이상 해요?
또한이 경우
function a() {}
똑같이 행동했다
var a = function () {};
따라서 본질적으로 코드가 수행하는 작업은 다음과 같습니다.
var a = 1; //defines "a" in global scope
function b() {
var a = function () {}; //defines "a" in local scope
a = 10; //overwrites local variable "a"
return;
}
b();
alert(a); //alerts global variable "a"
기억해야 할 것은 전체 함수를 구문 분석하고 실행하기 전에 모든 변수 선언을 해결한다는 것입니다. 그래서....
function a() {}
정말로된다
var a = function () {}
var a
로컬 범위로 강제하고 변수 범위는 전체 함수를 통하므로 전역 변수는 여전히 1입니다.을 함수로 만들어서 로컬 범위로 선언했기 때문입니다.
기능 a
은 기능 내부에 게양됩니다 b
.
var a = 1;
function b() {
function a() {}
a = 10;
return;
}
b();
alert(a);
거의 다음을 사용하는 것과 같습니다 var
.
var a = 1;
function b() {
var a = function () {};
a = 10;
return;
}
b();
alert(a);
함수는 로컬로 선언되며 설정 a
은 전역 var가 아닌 로컬 범위에서만 발생합니다.
- 함수 선언
function a(){}
이 먼저 호이스트되고처럼 동작var a = function () {};
하므로 로컬 범위a
에서 생성됩니다. - 같은 이름의 변수가 두 개있는 경우 (하나는 전역에서 다른 하나는 로컬에서) 지역 변수는 항상 전역 변수보다 우선합니다.
- 를 설정 하면 전역
a=10
변수a
가 아닌 로컬 변수가 설정 됩니다.
따라서 전역 변수의 값은 동일하게 유지되고 경고 1이 표시됩니다.
function a() { }
함수에 a
로컬 변수 를 생성하는 함수 문 b
입니다. 또는 function 문이 실행
되는지 여부에 관계없이 함수가 구문 분석 될 때 변수가 생성됩니다 var
.
a = 10
이 지역 변수를 설정합니다.
scpope 및 폐쇄 및 호이 스팅 (var / function)
- scpope : 전역 변수는 모든 위치 (전체 파일 범위)에서 액세스 할 수 있으며, 로컬 변수는 로컬 범위 (함수 / 블록 범위)에서만 액세스 할 수 있습니다!
참고 : 함수에서 var 키워드를 사용하지 않는 지역 변수는 전역 변수가됩니다!- 클로저 : 로컬 스코프 (부모 함수)와 글로벌 스코프에 접근 할 수있는 다른 함수 내부의 함수, 그러나 변수가 다른 사람이 접근 할 수없는 경우! 그렇지 않으면 반환 값으로 반환하십시오!
- hoisting : 값 또는 null을 할당하는 것보다 vars / function 선언 / 선언을 모두 스코프 맨 위로 이동합니다!
참고 : 값을 이동하지 않고 선언 만 이동합니다!
var a = 1;
//"a" is global scope
function b() {
var a = function () {};
//"a" is local scope
var x = 12;
//"x" is local scope
a = 10;
//global variable "a" was overwrited by the local variable "a"
console.log("local a =" + a);
return console.log("local x = " + x);
}
b();
// local a =10
// local x = 12
console.log("global a = " + a);
// global a = 1
console.log("can't access local x = \n");
// can't access local x =
console.log(x);
// ReferenceError: x is not defined
이 작은 코드 조각에서 경합의 뼈대는 무엇입니까?
사례 1 :
다음과 같이 function a(){}
본문에 정의를 포함 function b
합니다.logs value of a = 1
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
console.log(a); // logs a = 1
사례 2
다음과 같이 function a(){}
본문 내부의 정의를 제외 function b
합니다.logs value of a = 10
var a = 1;
function b() {
a = 10; // overwrites the value of global 'var a'
return;
}
b();
console.log(a); // logs a = 10
관찰은 명령문 console.log(a)
이 다음 값을 기록 한다는 사실을 깨닫는 데 도움이 됩니다.
사례 1 : a = 1
사례 2 : a = 10
Posits
var a
전역 범위에서 어휘 적으로 정의되고 선언되었습니다.a=10
이 문은 값을 10으로 재 할당하고 있으며 어휘 적으로 함수 b 내에 있습니다.
두 경우에 대한 설명
로 인해 function definition with name property
(A)가 동일하다 variable a
. variable a
내부는 function body b
로컬 변수가된다. 이전 행은 a의 전역 값이 그대로 유지되고 a의 로컬 값이 10으로 업데이트됨을 의미합니다.
그래서 우리가 말하고자하는 것은 아래 코드가
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
console.log(a); // logs a = 1
JS 인터프리터는 다음과 같이 해석합니다.
var a = 1;
function b() {
function a() {}
a = 10;
return;
}
b();
console.log(a); // logs a = 1
그러나 함수 b 외부 function a(){} definition
에서 value of 'a'
선언되고 정의 된 ,를 제거하면 해당 값을 덮어 쓰고 경우 2에서 10으로 변경 a=10
합니다. 전역 선언을 참조하기 때문에 값이 덮어 쓰여지고 로컬로 선언 된 경우 서면 var a = 10;
.
var a = 1;
function b() {
var a = 10; // here var a is declared and defined locally because it uses a var keyword.
return;
}
b();
console.log(a); // logs a = 1
우리는 변화에 의해 우리의 의심을 더욱 명확히 할 수 name property
있는을 function a(){} definition
다른 이름보다'a'
var a = 1;
function b() {
a = 10; // here var a is declared and defined locally because it uses a var keyword.
return;
function foo() {}
}
b();
console.log(a); // logs a = 1
호이 스팅은 이해하기 쉽도록 만든 개념입니다. 실제로 발생하는 것은 범위와 관련하여 선언이 먼저 수행되고 그 이후에 할당이 수행됩니다 (동시에 아님).
선언이 발생하는 경우 var a
, 다음 function b
그 안에 b
범위 function a
선언된다.
이 함수 a는 전역 범위에서 오는 변수 a를 숨 깁니다.
선언이 완료되면 값 할당이 시작되고 전역 a
값이 값 을 얻고 1
내부 값 function b
이 10
. 할 때 alert(a)
실제 전역 범위 변수를 호출합니다. 코드를 조금만 변경하면 더 명확 해집니다.
var a = 1;
function b() {
a = 10;
return a;
function a() { }
}
alert(b());
alert(a);
변수 이름이 함수 이름이 "a"를 의미하는 것과 동일하기 때문에 발생합니다. 따라서 Javascript 호이 스팅으로 인해 이름 충돌을 해결하려고 시도하고 a = 1을 반환합니다.
또한 "JavaScript Hoisting" http://www.ufthelp.com/2014/11/JavaScript-Hoisting.html 에 대한이 게시물을 읽을 때까지 이것에 대해 혼란 스러웠습니다 .
도움이 되었기를 바랍니다.
여기에 더 많은 주석과 함께 연주 할 수있는 바이올린이있는 대답에 대한 요약이 있습니다.
// hoisting_example.js
// top of scope ie. global var a = 1
var a = 1;
// new scope due to js' functional (not block) level scope
function b() {
a = 10; // if the function 'a' didn't exist in this scope, global a = 10
return; // the return illustrates that function 'a' is hoisted to top
function a(){}; // 'a' will be hoisted to top as var a = function(){};
}
// exec 'b' and you would expect to see a = 10 in subsequent alert
// but the interpreter acutally 'hoisted' the function 'a' within 'b'
// and in doing so, created a new named variable 'a'
// which is a function within b's scope
b();
// a will alert 1, see comment above
alert(a);
https://jsfiddle.net/adjavaherian/fffpxjx7/
Hoisting JavaScript에서 변수 선언은 코드가 실행되기 전에 프로그램을 통해 실행됩니다. 따라서 코드의 어느 위치에서나 변수를 선언하는 것은 처음에 선언하는 것과 같습니다.
모두 변수 'a'의 범위에 따라 다릅니다. 스코프를 이미지로 만들어 설명하겠습니다.
여기서 JavaScript는 3 개의 범위를 생성합니다.
i) 글로벌 범위. ii) 함수 b () 범위. iii) 함수 a () 범위.
'alert'메소드 범위를 호출하면 해당 시간이 Global에 속하므로 Global 범위에서 변수 'a'의 값이 1 인 값만 선택합니다.
긴 포스트!
그러나 그것은 공기를 맑게 할 것입니다!
Java Script가 작동하는 방식은 두 단계 프로세스를 포함한다는 것입니다.
컴파일 (말하자면)-이 단계는 변수와 함수 선언 및 해당 범위를 등록합니다. 이 평가 함수식 포함하지 않는다 :
var a = function(){}
(할당 등 또는 가변 식3
으로x
경우의var x =3;
. 이는 아무것도하지만 RHS 부의 평가 없음)통역사 : 실행 / 평가 부분입니다.
이해하려면 아래 코드의 출력을 확인하십시오.
//b() can be called here!
//c() cannot be called.
console.log("a is " + a);
console.log("b is " + b);
console.log("c is " + c);
var a = 1;
console.log("Now, a is " + a);
var c = function() {};
console.log("Now c is " + c);
function b() {
//cannot write the below line:
//console.log(e);
//since e is not declared.
e = 10; //Java script interpreter after traversing from this function scope chain to global scope, is unable to find this variable and eventually initialises it with value 10 in global scope.
console.log("e is " + e) // works!
console.log("f is " + f);
var f = 7;
console.log("Now f is " + f);
console.log("d is " + d);
return;
function d() {}
}
b();
console.log(a);
그것을 깨자 :
컴파일 단계에서 'a'는 값이 '
undefined
'인 전역 범위 아래에 등록됩니다 . 'c
'도 마찬가지입니다 .이 순간의 값은 'undefined
'가 아니라 'function()
'입니다. 'b
'은 전역 범위의 함수로 등록됩니다. 내부b
의 범위는 'f
'이 순간과 기능 "으로 정의되지 유용한 변수로 등록 될d
등록된다 '.인터프리터가 실행되면 인터프리터가
function()
실제 표현식 라인에 도달하기 전에 선언 된 변수 (식이 아닌)에 액세스 할 수 있습니다. 따라서 변수는 'undefined
' 로 인쇄 되고 선언 된 익명 함수를 더 일찍 호출 할 수 있습니다. 그러나 표현식 초기화 전에 선언되지 않은 변수에 액세스하려고하면 다음과 같은 오류가 발생합니다.
console.log(e)
e = 3;
이제 같은 이름의 변수와 함수 선언이 있으면 어떻게됩니까?
대답은 -함수는 항상 이전에 호이스트되며 동일한 이름 변수가 선언되면 중복으로 처리되고 무시됩니다. 순서는 중요하지 않습니다. 함수에는 항상 우선 순위가 있습니다. 그러나 평가 단계에서 변수 참조를 무엇이든 변경할 수 있습니다 (마지막 할당을 저장합니다). 아래 코드를 살펴보십시오.
var a = 1;
console.log("a is " + a);
function b() {
console.log("a inside the function b is " + a); //interpreter finds 'a' as function() in current scope. No need to go outside the scope to find 'a'.
a = 3; //a changed
console.log("Now a is " + a);
return;
function a() {}
}
var a; //treated as duplicate and ignored.
b();
console.log("a is still " + a + " in global scope"); //This is global scope a.
Hoisting은 JavaScript의 동작 개념입니다. 호이 스팅 (이동)은 변수를 선언하는 방법과 위치를 설명하는 개념입니다.
JavaScript에서는 함수 선언과 변수 선언이 JavaScript 인터프리터에 의해 포함 된 범위의 맨 위로 항상 보이지 않게 이동 ( "게재")되기 때문에 JavaScript에서 변수를 사용한 후에 선언 할 수 있습니다.
대부분의 경우 두 가지 유형의 호이 스팅이 발생합니다.
1. 가변 선언 게양
이 코드 조각으로 이것을 이해할 수 있습니다.
a = 5; // Assign 5 to a
elem = document.getElementById("demo"); // Find an element
elem.innerHTML = a; // Display a in the element
var a; // Declare a
//output-> 5
여기서 변수 a의 선언은 컴파일 할 때 자바 스크립트 인터프리터에 의해 보이지 않게 맨 위에 호스팅됩니다. 그래서 우리는 a의 가치를 얻을 수있었습니다. 그러나 이러한 변수 선언 접근 방식은 이미 이와 같이 변수를 맨 위에 선언해야하므로 권장되지 않습니다.
var a = 5; // Assign and declare 5 to a
elem = document.getElementById("demo"); // Find an element
elem.innerHTML = a; // Display a in the element
// output -> 5
다른 예를 고려하십시오.
function foo() {
console.log(x)
var x = 1;
}
실제로 다음과 같이 해석됩니다.
function foo() {
var x;
console.log(x)
x = 1;
}
이 경우 x는 정의되지 않습니다.
변수 선언을 포함하는 코드가 실행되었는지 여부는 중요하지 않습니다. 이 예를 고려하십시오.
function foo() {
if (false) {
var a = 1;
}
return;
var b = 1;
}
이 기능은 다음과 같습니다.
function foo() {
var a, b;
if (false) {
a = 1;
}
return;
b = 1;
}
변수 선언에서는 할당이 아닌 변수 정의 만 호이스트합니다.
- 기능 선언 게양
가변 호이스트와 달리 기능 본체 또는 할당 된 값도 호이스트됩니다. 이 코드를 고려하십시오
function demo() {
foo(); // this will give error because it is variable hoisting
bar(); // "this will run!" as it is function hoisting
var foo = function () {
alert("this would not run!!");
}
function bar() {
alert("this will run!!");
}
}
demo();
이제 변수 및 함수 호이 스팅을 모두 이해 했으므로 이제이 코드를 이해하겠습니다.
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);
이 코드는 다음과 같습니다.
var a = 1; //defines "a" in global scope
function b() {
var a = function () {}; //defines "a" in local scope
a = 10; //overwrites local variable "a"
return;
}
b();
alert(a);
함수 a ()는 b () 내부에 지역 범위를 갖습니다. a ()는 정의 (함수 호이 스팅의 경우에만 해당)로 코드를 해석하는 동안 맨 위로 이동하므로 a는 이제 로컬 범위를 가지므로 a의 전역 범위에는 영향을주지 않지만 함수 b () 내에 자체 범위가 있습니다. .
놀랍게도 여기에 언급 된 답변 중 어느 것도 범위 체인에서 실행 컨텍스트의 관련성을 언급하지 않습니다.
JavaScript 엔진은 현재 실행중인 코드를 실행 컨텍스트에 래핑합니다. 기본 실행 컨텍스트는 전역 실행 컨텍스트입니다. 새 함수가 호출 될 때마다 새 실행 컨텍스트가 생성되고 실행 스택에 배치됩니다. 다른 프로그래밍 언어에서 호출 스택에있는 스택 프레임을 생각해보십시오. 후입 선출법. 이제 각 실행 컨텍스트에는 JavaScript의 자체 변수 환경과 외부 환경이 있습니다.
아래 예제를 데모로 사용하겠습니다.
1) 먼저 글로벌 실행 컨텍스트의 생성 단계에 들어갑니다. Lexical Environment의 외부 환경과 가변 환경이 모두 생성됩니다. 전역 개체가 설정되고이를 가리키는 특수 변수 'this'와 함께 메모리에 배치됩니다. 함수 a와 해당 코드 및 정의되지 않은 값을 가진 myVar 변수는 전역 변수 환경의 메모리에 배치됩니다. 함수 a의 코드가 실행되지 않는다는 점에 유의하는 것이 중요합니다. 기능 a와 함께 메모리에 저장됩니다.
2) 둘째, 실행 컨텍스트의 실행 단계입니다. myVar는 더 이상 정의되지 않은 값이 아닙니다. 값 1로 초기화되며 전역 변수 환경에 저장됩니다. 함수 a가 호출되고 새 실행 컨텍스트가 생성됩니다.
3) 함수 a의 실행 컨텍스트에서 자체 실행 컨텍스트의 생성 및 실행 단계를 거칩니다. 자체 외부 환경과 가변 환경이 있으므로 자체 어휘 환경이 있습니다. 함수 b와 변수 myVar는 변수 환경에 저장됩니다. 이 변수 환경은 전역 변수 환경과 다릅니다. 함수 a는 전역 실행 컨텍스트와 동일한 수준에서 어휘 적으로 (물리적으로 코드에서) 위치하므로 외부 환경은 전역 실행 컨텍스트입니다. 따라서 함수 a가 변수 환경에없는 변수를 참조하는 경우 스코프 체인을 검색하고 글로벌 실행 컨텍스트의 변수 환경에서 변수를 찾으려고합니다.
4) 함수 b는 함수 a에서 호출됩니다. 새 실행 컨텍스트가 생성됩니다. 함수 a에 어휘 적으로 있기 때문에 외부 환경은 a입니다. 따라서 myVar를 참조 할 때 myVar는 함수 b의 변수 환경에 없기 때문에 함수 a의 변수 환경을 찾습니다. 거기에서 그것을 찾고 console.log는 2를 인쇄합니다. 그러나 변수가 함수 a의 변수 환경에 없다면, 함수 a의 외부 환경이 전역 실행 컨텍스트이기 때문에 스코프 체인은 그곳에서 계속 검색 할 것입니다.
5) 함수 b와 a가 실행을 마치면 Execution Stack에서 팝됩니다. 단일 스레드 JavaScript 엔진은 전역 실행 컨텍스트에서 계속 실행됩니다. b 함수를 호출합니다. 그러나 전역 변수 환경에는 b 함수가 없으며 전역 실행 컨텍스트에서 검색 할 다른 외부 환경이 없습니다. 따라서 JavaScript 엔진에서 예외가 발생합니다.
function a(){
function b(){
console.log(myVar);
}
var myVar = 2;
b();
}
var myVar = 1;
a();
b();
> 2
> Uncaught ReferenceError: b is not defined
아래 예는 작동중인 스코프 체인을 보여줍니다. 함수 b의 실행 컨텍스트의 변수 환경에는 myVar가 없습니다. 그래서 그것은 기능인 외부 환경을 검색합니다. 함수 a에는 변수 환경에도 myVar가 없습니다. 따라서 엔진 검색 함수 a의 외부 환경은 전역 실행 컨텍스트의 외부 환경이고 myVar가 여기에 정의되어 있습니다. 따라서 console.log는 1을 인쇄합니다.
function a(){
function b(){
console.log(myVar);
}
b();
}
var myVar = 1;
a();
> 1
실행 컨텍스트 및 외부 환경 및 변수 환경을 포함하여 연관된 어휘 환경과 관련하여 JavaScript에서 변수 범위 지정을 활성화합니다. 동일한 함수를 여러 번 호출하더라도 각 호출에 대해 고유 한 실행 컨텍스트를 생성합니다. 따라서 각 실행 컨텍스트는 변수 환경에서 자체 변수 사본을 갖습니다. 변수 공유가 없습니다.
내 지식으로 볼 때 변수 선언 및 함수 선언과 함께 호이 스팅이 발생합니다.
a = 7;
var a;
console.log(a)
자바 스크립트 엔진 내부에서 일어나는 일 :
var a;
a = 7;
console.log(a);
// 7
또는:
console.log(square(7)); // Output: 49
function square(n) { return n * n; }
다음과 같이됩니다.
function square(n) { return n * n; }
console.log(square(7)); // 49
그러나 변수 할당, 함수 표현식 할당과 같은 할당은 호이스트되지 않습니다. 예 :
console.log(x);
var x = 7; // undefined
다음과 같이 될 수 있습니다.
var x;
console.log(x); // undefined
x = 7;
참고 URL : https://stackoverflow.com/questions/7506844/javascript-function-scoping-and-hoisting
'program story' 카테고리의 다른 글
C #에서 익명 메서드에 yield 문을 포함 할 수없는 이유는 무엇입니까? (0) | 2020.09.19 |
---|---|
'IEnumerable'유형의 ViewData 항목이 없습니다. (0) | 2020.09.19 |
angular.js에서 HTML5 pushstate 사용 (0) | 2020.09.19 |
WCF가 기준을 높이거나 복잡성 수준을 높입니까? (0) | 2020.09.19 |
Intellij에서 Java 디버거를 사용할 때 "드롭 프레임"은 무엇을 의미합니까? (0) | 2020.09.19 |