>  기사  >  웹 프론트엔드  >  Javascript 범위 및 변수 Promotion_javascript 기술에 대한 심층적인 이해

Javascript 범위 및 변수 Promotion_javascript 기술에 대한 심층적인 이해

WBOY
WBOY원래의
2016-05-16 17:10:181057검색

다음 프로그램의 결과는 무엇입니까?

코드 복사 코드는 다음과 같습니다.

var foo = 1;
function bar() {
if (!foo) {
var foo = 10;
}
Alert(foo);
}
bar();

결과는 10입니다.

다음은 어떻습니까?

코드 복사 코드는 다음과 같습니다.

var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);

결과는 1입니다.

놀랐나요? 무슨 일이에요? 이는 이상하고 위험하며 혼란스러울 수 있지만 실제로는 매우 유용하고 인상적인 JavaScript 언어 기능이기도 합니다. 이 동작에 대한 표준 이름이 있는지는 모르겠지만 저는 "호이스팅"이라는 용어를 좋아합니다. 이 기사에서는 이 메커니즘에 대한 소개 설명을 제공하지만 먼저 JavaScript의 범위에 대해 필요한 몇 가지 이해를 해보겠습니다.

자바스크립트의 범위

Javascript 초보자에게 가장 혼란스러운 점 중 하나는 범위입니다. 사실 이는 초보자만이 아닙니다. 나는 숙련된 JavaScript 프로그래머들을 만났지만 그들은 범위를 깊이 이해하지 못했습니다. JavaScript 범위가 혼란스러운 이유는 프로그램 구문 자체가 다음 C 프로그램처럼 C 계열 언어처럼 보이기 때문입니다.

코드 복사 코드는 다음과 같습니다.

#include
int main() {
int x = 1;
printf("%d, ", x); // 1
if (1) {
int x = 2;
printf("%d, ", x); // 2
}
printf( "% dn", x); // 1
}

출력 결과는 1 2 1입니다. 이는 C 계열 언어에 블록 범위가 있기 때문입니다. If 블록과 같이 블록 외부의 범위에는 영향을 주지 않고 블록에만 영향을 주는 변수를 선언할 수 있습니다. 하지만 자바스크립트에서는 이것이 작동하지 않습니다. 아래 코드를 살펴보세요.
코드를 복사하세요. 코드는 다음과 같습니다.

var x = 1;
console.log(x); // 1
if(true) {
var x = 2;
console.log(x) // 2
}
console.log(x); // 2

결과는 1 2 2입니다. 자바스크립트는 함수 범위이기 때문입니다. 이것이 C 언어 계열과의 가장 큰 차이점입니다. 이 프로그램의 if는 새 범위를 생성하지 않습니다.

많은 C, C, Java 프로그래머에게 이는 기대하고 환영하는 내용이 아닙니다. 다행히도 JavaScript 함수의 유연성으로 인해 이 문제를 해결할 수 있는 방법이 있습니다. 임시 범위를 만들어야 하는 경우 다음과 같이 할 수 있습니다.

코드 복사 코드는 다음과 같습니다.

function foo() {
var x = 1;
if (x) {
(function () {
var x = 2;
// 일부 other code
}());
}
// x는 여전히 1입니다.
}

이 방법은 매우 유연하며 원하는 곳 어디에서나 사용할 수 있습니다. 임시 범위 장소를 만듭니다. 블록 내에서만이 아닙니다. 그러나 JavaScript 범위 지정을 이해하는 데 시간을 할애하는 것이 좋습니다. 이는 매우 유용하며 제가 가장 좋아하는 JavaScript 기능 중 하나입니다. 범위를 이해한다면 변수 호이스팅이 더 이해가 될 것입니다.

변수 선언, 이름 지정 및 승격

JavaScript에는 변수가 범위에 들어가는 기본 방법이 4가지 있습니다.

•1 언어 내장: 모든 범위에는 이 인수와 인수가 있습니다. (번역자 참고: 테스트 후에 인수는 전역 범위에 표시되지 않습니다.)

•2 형식 매개변수: 함수의 형식 매개변수는 함수 본문 범위의 일부입니다.

•3 함수 선언: 다음 형식과 같습니다: function foo(){}

•4 변수 선언: 다음과 같습니다: var foo

함수 선언과 변수 선언은 항상 인터프리터에 의해 메서드 본문의 맨 위로 조용히 "승격"됩니다. 이는 다음 코드와 같습니다.


코드 복사 코드는 다음과 같습니다.
function foo( ) {
bar();
var x = 1;
}


은 실제로 다음과 같이 해석됩니다.
코드 복사 코드는 다음과 같습니다.

function foo () {
var x;
bar();
x = 1;
}

변수가 정의된 블록 여부에 관계 없음 실행될 수 있습니다. 다음 두 함수는 실제로는 같습니다.
코드 복사 코드는 다음과 같습니다.

function foo() {
if (false) {
var x = 1;
}
return;
var y = 1;
}
function foo( ) {
var x, y;
if (false) {
x = 1;
}
return;
y = 1;
}

변수 할당은 호이스팅되지 않고 선언만 된다는 점에 유의하세요. 그러나 함수 선언이 조금 다르며 함수 본문도 승격됩니다. 하지만 함수를 선언하는 방법에는 두 가지가 있습니다.
코드 복사 코드는 다음과 같습니다.

function test() {
foo(); // TypeError "foo는 함수가 아닙니다."
bar(); // "이것이 실행됩니다!"
var foo = function () { // 함수 표현식을 가리키는 변수
Alert("이것은 실행되지 않습니다!");
}
function bar() { // 함수 선언 함수 이름은 bar입니다
Alert("this will run!" );
}
}
test();

이 예에서는 함수 선언만 함수 본문과 함께 승격됩니다. foo 선언은 호이스팅되지만, 그것이 가리키는 함수 본문은 실행 중에만 할당됩니다.

위 내용은 부스팅의 기본 사항 중 일부를 다루고 있으며 그다지 혼란스럽지 않은 것 같습니다. 그러나 일부 특수한 시나리오에서는 여전히 어느 정도의 복잡성이 존재합니다.

변수 파싱 순서

가장 중요한 점은 변수 해상도의 순서입니다. 앞서 제공한 범위에 이름 지정이 들어가는 4가지 방법을 기억하시나요? 변수가 구문 분석되는 순서는 내가 나열한 순서입니다.

코드 복사 코드는 다음과 같습니다.

<script><br>function a (){ <br>}<br>var a;<br>alert(a);//a<br></script>의 함수 본문을 인쇄합니다.

<스크립트>

var a;
function a(){
}
alert(a);//a

의 함수 본문을 인쇄합니다.//그러나 주의 다음 두 가지 작성 방법의 차이점을 구별하세요.
<script><br>var a=1;<br>function a(){ <br>}<br>alert(a);//인쇄 1<br></script>

<script><br>함수 a(){ <br>}</p> <p>var a=1;</p> <p>alert(a);//1개 인쇄<br></script>


여기에는 3가지 예외가 있습니다.

1 내장된 이름 인수가 이상하게 동작합니다. 함수 형식 매개변수 뒤에 선언해야 하지만 함수 선언 전에 선언해야 하는 것 같습니다. 즉, 형식 매개변수에 인수가 있으면 내장 매개변수보다 우선순위가 높습니다. 이는 매우 나쁜 기능이므로 형식 매개변수에 인수를 사용하지 마세요.

2 이 변수를 어디에서나 정의하면 구문 오류가 발생하는데 이는 좋은 기능입니다.

3 여러 형식 매개변수가 동일한 이름을 갖는 경우 실제 작업 중에 해당 값이 정의되지 않은 경우에도 마지막 매개변수가 우선순위를 갖습니다.

이름이 지정된 함수

함수에 이름을 지정할 수 있습니다. 그렇다면 함수 선언이 아니며, 함수 본문 정의에 지정된 함수 이름(있는 경우 아래 스팸, 번역자 메모)은 승격되지 않고 무시됩니다. 이해를 돕기 위한 코드는 다음과 같습니다.

코드 복사 코드는 다음과 같습니다.

foo(); / / TypeError "foo는 함수가 아닙니다"
bar(); // valid
baz(); // TypeError "baz는 함수가 아닙니다"
spam(); / ReferenceError "스팸이 정의되지 않았습니다."

var foo = function () {}; // foo는 익명 함수를 가리킵니다.
function bar() {} // 함수 선언
var baz = function spam() {}; 기능, baz만 승격되며 스팸은 승격되지 않습니다.

foo(); // 유효함
bar(); // 유효함
spam(); // 참조 오류 "스팸이 정의되지 않았습니다" 🎜>
코드 작성 방법

이제 범위 지정과 변수 호이스팅을 이해했으므로 이것이 JavaScript 코딩에 어떤 의미가 있나요? 가장 중요한 것은 항상 var를 사용하여 변수를 정의하는 것입니다. 그리고 이름의 경우 범위에 항상 하나의 var 선언만 있어야 한다고 강력히 권장합니다. 이렇게 하면 범위 및 변수 호이스팅 문제가 발생하지 않습니다.

언어 사양 말하는 방법

저는 ECMAScript 참조 문서가 항상 도움이 된다고 생각합니다. 범위 지정 및 변수 호이스팅에 대해 제가 찾은 내용은 다음과 같습니다.

함수 본문 클래스에 변수가 선언되면 함수 범위입니다. 그렇지 않으면 전역 범위가 지정됩니다(global 속성으로). 실행이 범위에 들어갈 때 변수가 생성됩니다. 블록은 새로운 범위를 정의하지 않으며, 함수 선언과 프로시저(번역자는 전역 코드 실행이라고 생각함)만이 새로운 범위를 생성합니다. 변수는 생성될 때 정의되지 않음으로 초기화됩니다. 변수 선언문에 대입 연산이 있는 경우 변수 생성 시가 아니라 실행 시에만 대입 연산이 발생합니다.

이 기사가 JavaScript에 대해 혼란스러워하는 프로그래머들에게 한 줄기 빛을 가져다주기를 바랍니다. 저 역시 더 이상의 혼란을 야기하지 않도록 최선을 다하겠습니다. 제가 말을 잘못했거나 간과한 부분이 있으면 알려주세요.

번역가의 보충 자료

친구가 IE에서 전역 범위에서 명명된 함수를 개선하는 문제를 발견했다고 상기시켜주었습니다.

기사를 번역하면서 테스트한 내용입니다:

코드 복사 코드는 다음과 같습니다.

<script><br>functiont(){<br>spam();<br>var baz = function spam() {alert('스팸입니다')};<br>}<br>t() ;<br></script>

이러한 작성 방식, 즉 비전역 범위에서 명명된 함수를 승격하는 것은 IE와 FF에서 동일한 성능을 갖습니다. .
코드 복사 코드는 다음과 같습니다.

spam();
var baz = function spam() {alert('this is spam')};


그러면 스팸은 다음과 같습니다. ie에서는 실행되지만 ff에서는 실행되지 않습니다. 설명 브라우저마다 이 세부정보를 다르게 처리합니다. 이 질문으로 인해 두 가지 다른 질문도 생각하게 되었습니다. 1: 범위에서 전역적으로 작동하는 변수의 경우 var와 non-var 간에 차이가 있습니다. var가 없으면 변수가 승격되지 않습니다. 예를 들어, 다음 두 프로그램 중 두 번째 프로그램은 오류를 보고합니다.


코드 복사 코드는 다음과 같습니다.
<script><br>alert(a);<br>var a=1;<br></script>


코드 복사 코드는 다음과 같습니다.
<script><br>alert(a);<br>a =1;<br></script>

2: eval에서 생성된 지역 변수는 승격되지 않습니다(승격할 방법이 없습니다).

코드 복사 코드는 다음과 같습니다.
<script><br>var a = 1;<br>function t( ){<br> 경고(a);<br> eval('var a = 2');<br> 경고(a);<br>}<br>t();<br>alert(a); <br></script>

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.