암시적 전역 변수
지역 변수
변수 선언 호이스팅(Hoisting)
이름 확인 순서
네임스페이스
결론
JavaScript는 지원하지만 중괄호 쌍으로 생성된 코드 조각은 블록 수준 범위를 지원하지 않고 함수 범위만 지원합니다.
function test() { // 一个作用域 for(var i = 0; i < 10; i++) { // 不是一个作用域 // count } console.log(i); // 10 }
번역자 주의 사항: 반환 개체의 왼쪽 대괄호와 return이 같은 줄에 있지 않으면 오류가 발생합니다.
(참고: 대입문이 아니라 반환 표현식 또는 함수 매개변수에 있는 경우 {...}는 리터럴 구문 분석이 아닌 코드 세그먼트로 구문 분석됩니다. 자동 세미콜론 삽입을 고려하면 미묘한 오류가 발생할 수 있습니다.)
// 译者注:下面输出 undefined function add(a, b) { return a + b; } console.log(add(1, 2));
JavaScript에는 명시적인 네임스페이스 정의가 없습니다. 즉, 모든 객체는 아래에 정의됩니다. 전역적으로 공유되는 네임스페이스.
변수가 참조될 때마다 JavaScript는 변수를 찾을 때까지 전체 범위를 위쪽으로 탐색합니다. 전역 범위에 도달했지만 여전히 변수를 찾을 수 없으면 ReferenceError 예외가 발생합니다.
암시적 전역 변수
// 脚本 A foo = '42'; // 脚本 B var foo = '42'
위의 두 스크립트는 효과가 다릅니다. 스크립트 A는 전역 범위에서 foo 변수를 정의하고, 스크립트 B는 현재 범위에서 변수 foo를 정의합니다.
다시 한번 말씀드리지만, var를 사용하지 않고 변수를 선언하면 암시적 전역 변수가 생성됩니다.
// 全局作用域 var foo = 42; function test() { // 局部作用域 foo = 21; } test(); foo; // 21
함수 테스트 내에서 var 키워드를 사용하지 않고 foo 변수를 선언하면 동일한 이름으로 외부 변수를 덮어쓰게 됩니다. 처음에는 큰 문제가 아닌 것처럼 보일 수도 있지만 수천 줄의 코드가 있는 경우 var를 사용하지 않고 변수를 선언하면 추적하기 어려운 버그가 발생할 수 있습니다.
// 全局作用域 var items = [/* 数组 */]; for(var i = 0; i < 10; i++) { subLoop(); } function subLoop() { // subLoop 函数作用域 for(i = 0; i < 10; i++) { // 没有使用 var 声明变量 // 干活 } }
subLoop가 전역 변수 i를 덮어쓰기 때문에 subLoop에 대한 첫 번째 호출 후에 외부 루프가 종료됩니다. 두 번째 for 루프에서 var를 사용하여 변수를 선언하면 이 오류를 피할 수 있습니다. 외부 범위에 영향을 미치는 바람직한 동작이 아닌 이상 변수를 선언할 때 var 키워드를 생략하지 마십시오.
지역 변수
JavaScript의 지역 변수는 두 가지 방법으로만 선언할 수 있습니다. 하나는 함수 매개변수로 선언하고 다른 하나는 var 키워드를 통해 선언합니다.
// 全局变量 var foo = 1; var bar = 2; var i = 2; function test(i) { // 函数 test 内的局部作用域 i = 5; var foo = 3; bar = 4; } test(10);
foo와 i는 test 함수 내의 지역 변수이며 bar에 할당하면 전역 범위에서 동일한 이름으로 변수를 덮어씁니다.
변수 선언 호이스팅(Hoisting)
자바스크립트는 변수 선언을 호이스팅합니다. 즉, var 표현식과 함수 선언이 모두 현재 범위의 맨 위로 끌어올려집니다.
bar(); var bar = function() {}; var someValue = 42; test(); function test(data) { if (false) { goo = 1; } else { var goo = 2; } for(var i = 0; i < 100; i++) { var e = data[i]; } }
위 코드는 실행 전 변환됩니다. JavaScript는 var 표현식과 함수 선언을 현재 범위의 맨 위로 끌어올립니다.
// var 表达式被移动到这里 var bar, someValue; // 缺省值是 'undefined' // 函数声明也会提升 function test(data) { var goo, i, e; // 没有块级作用域,这些变量被移动到函数顶部 if (false) { goo = 1; } else { goo = 2; } for(i = 0; i < 100; i++) { e = data[i]; } } bar(); // 出错:TypeError,因为 bar 依然是 'undefined' someValue = 42; // 赋值语句不会被提升规则(hoisting)影响 bar = function() {}; test();
블록 범위가 없으면 var 표현식이 루프 내부에서 외부로 이동될 뿐만 아니라 일부 if 표현식을 읽기가 더 어려워집니다.
원래 코드에서 if 표현식은 전역 변수 goo를 수정하는 것처럼 보이지만 실제로는 승격 규칙이 적용된 후에 지역 변수를 수정합니다.
호이스팅에 대한 지식이 없으면 다음 코드는 ReferenceError 예외를 발생시키는 것으로 나타납니다.
// 检查 SomeImportantThing 是否已经被初始化 if (!SomeImportantThing) { var SomeImportantThing = {}; }
실제로 위 코드는 var 표현식이 전역 범위의 맨 위로 끌어올려지기 때문에 제대로 작동합니다.
var SomeImportantThing; // 其它一些代码,可能会初始化 SomeImportantThing,也可能不会 // 检查是否已经被初始化 if (!SomeImportantThing) { SomeImportantThing = {}; }
번역자 주: Nettuts+ 웹사이트에 호이스팅을 소개하는 기사가 있는데, 그 안에 있는 코드가 매우 유익합니다.
// 译者注:来自 Nettuts+ 的一段代码,生动的阐述了 JavaScript 中变量声明提升规则 var myvar = 'my value'; (function() { alert(myvar); // undefined var myvar = 'local value'; })();
이름 확인 순서
전역 범위를 포함하여 JavaScript의 모든 범위에는 현재 개체를 가리키는 특별한 이름이 있습니다. 함수 범위에는 함수에 전달된 매개변수를 포함하는 기본 변수 인수도 있습니다. 예를 들어, 함수 내의 foo 변수에 액세스할 때 JavaScript는 다음 순서로 검색합니다.
현재 범위에 var foo 정의가 있는지 여부.
함수 형식 매개변수가 foo 이름을 사용하는지 여부입니다.
함수 자체를 foo라고 하는지.
이전 범위로 돌아가서 #1부터 다시 시작하세요.
네임스페이스
전역 범위가 하나만 있을 때 발생하는 일반적인 실수는 이름 충돌입니다. JavaScript에서는 익명 래퍼를 사용하여 이 문제를 쉽게 해결할 수 있습니다.
(참고: 사용자 정의 인수는 기본 인수 개체 생성을 방지합니다.)
(function() { // 函数创建一个命名空间 window.foo = function() { // 对外公开的函数,创建了闭包 }; })(); // 立即执行此匿名函数
익명 함수는 표현식으로 간주되므로 호출 가능성을 위해 먼저 실행됩니다.
( // 小括号内的函数首先被执行 function() {} ) // 并且返回函数对象 () // 调用上面的执行结果,也就是函数对象
함수 표현식을 호출하는 다른 방법이 있습니다. 예를 들어 다음 두 메서드는 구문이 다르지만 효과는 완전히 동일합니다.
// 另外两种方式 +function(){}(); (function(){}());
결론
네임스페이스를 생성하려면 익명 래퍼(번역자 주: 자체 실행 익명 함수)를 사용하는 것이 좋습니다. 이는 이름 충돌을 방지할 뿐만 아니라 프로그램의 모듈화를 촉진합니다.
또한 전역 변수를 사용하는 것은 나쁜 습관으로 간주됩니다. 이러한 코드는 오류가 발생하기 쉽고 유지 관리 비용이 많이 듭니다.
위는 JavaScript 고급 시리즈의 내용입니다. - 범위 및 네임스페이스 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 참고해주세요!