>웹 프론트엔드 >JS 튜토리얼 >JavaScript 범위에 대한 종합 분석(코드 포함)

JavaScript 범위에 대한 종합 분석(코드 포함)

不言
不言앞으로
2019-04-03 10:27:592169검색

이 글은 JavaScript 범위(코드 포함)에 대한 포괄적인 분석을 제공합니다. 도움이 필요한 친구들이 참고할 수 있기를 바랍니다.

범위는 변수의 수명주기와 가시성을 결정합니다.

JavaScript의 범위에는 모듈 범위, 함수 범위, 블록 범위, 어휘 범위 및 전역 범위가 포함됩니다.

전역 범위

함수, 블록 또는 모듈의 범위 외부에서 정의된 변수는 전역 범위를 갖습니다. 전역 변수는 프로그램의 어느 곳에서나 접근할 수 있습니다.

모듈 시스템이 활성화되면 전역 변수를 생성하는 것이 더 어려워지지만 여전히 수행할 수 있습니다. 함수 외부에서 선언해야 하는 변수를 HTML로 정의할 수 있으므로 전역 변수를 만들 수 있습니다.

<script>
  let GLOBAL_DATA = { value : 1};
</script>
console.log(GLOBAL_DATA);

모듈 시스템이 없을 때 전역 변수를 만드는 것이 훨씬 쉽습니다. 모든 파일의 함수 외부에서 선언된 변수는 전역 변수입니다.

전역 변수는 프로그램의 전체 수명 주기 동안 실행됩니다.

전역 변수를 생성하는 또 다른 방법은 프로그램의 어느 곳에서나 window 전역 개체를 사용하는 것입니다. window 全局对象:

window.GLOBAL_DATA = { value: 1 };

这样 GLOBAL_DATA 变量会随处可见。

console.log(GLOBAL_DATA)

不过你也知道这种做法是不好的。

模块作用域

如果不启用模块,在所有函数之外声明的变量是全局变量。在模块中,在函数外部声明的变量都是隐藏的,除非显式导出,否则不可用于其他模块。

导出使函数或对象可用于其他模块。在这个例子中,我从模块文件 sequence.js 中导出了一个函数:

// in sequence.js
export { sequence, toList, take };

当前模块可以通过导入来使用其他模块的函数或对象成。

import { sequence, toList, toList } from "./sequence";

在某种程度上,我们可以认为模块是一个自动执行的函数,它将 import 的数据作为输入,然后返回 export 的数据。

函数作用域

函数作用域意味着在函数中定义的参数和变量在函数内的任何位置都可见,但是在函数外部不可见。

下面是一个自动执行的函数,被称为IIFE。

(function autoexecute() {
    let x = 1;
})();
console.log(x);
//Uncaught ReferenceError: x is not defined

IIFE 的意思是立即调用函数表达式,是一个在定义后立即运行的函数。

var 声明的变量只有函数作用域。更重要的是,用 var 声明的变量被提升到其作用域的顶部。通过这种方式,可以在声明之前访问它们。看看下面的代码:

function doSomething(){
  console.log(x);
  var x = 1;
}
doSomething(); //undefined

这种事不会发生在 let 中。用 let 声明的变量只能在定义后访问。

function doSomething(){
  console.log(x);
  let x = 1;
}
doSomething();
//Uncaught ReferenceError: x is not defined

var 声明的变量可以在同一作用域下多次重新声明:

function doSomething(){
  var x = 1
  var x = 2;
  console.log(x);
}
doSomething();

letconst 声明的变量不能在同一作用域内重新声明:

function doSomething(){
  let x = 1
  let x = 2;
}
//Uncaught SyntaxError: Identifier 'x' has already been declared

也许我们可以不必关心这一点,因为 var 已经开始变得过时了。

块作用域

块作用域用花括号定义。它由 {} 分隔。

letconst 声明的变量可以受到块作用域的约束,只能在定义它们的块中访问。

思考下面这段关于 let 块范围的代码:

let x = 1;
{ 
  let x = 2;
}
console.log(x); //1

相反,var 声明不受块作用域的约束:

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

另一个常见问题是在循环中使用类似 setTimeout() 的异步操作。下面的循环代码将显示五次数字 5。

(function run(){
    for(var i=0; i<5; i++){
        setTimeout(function logValue(){
            console.log(i);         //5
        }, 100);
    }
})();

带有 let 声明的 for 循环语句在每次循环都会创建一个新的变量并设置到块作用域。下一段循环代码将会显示 0 1 2 3 4 5

(function run(){
  for(let i=0; i<5; i++){
    setTimeout(function log(){
      console.log(i); //0 1 2 3 4
    }, 100);
  }
})();

词法作用域

词法作用域是内部函数访问定义它的外部作用域的能力。

看一下这段代码:

(function autorun(){
    let x = 1;
    function log(){
      console.log(x);
    };
    
    function run(fn){
      let x = 100;
      fn();
    }
    
    run(log);//1
})();

log 函数是一个闭包。它从父函数 autorun() 引用 x 变量,而不是 run() 函数中的 x 变量。

闭包函数可以访问创建它的作用域,而不是它自己的作用域。

autorun() 的局部函数作用域是 log() 函数的词法作用域。

作用域链

每个作用域都有一个指向父作用域的链接。当使用变量时,JavaScript 会向下查看作用域链,直到它找到所请求的变量或者到达全局作用域(即作用域链的末尾)。
看下面这个例子:

let x0 = 0;
(function autorun1(){
 let x1 = 1;
  
 (function autorun2(){
   let x2 = 2;
  
   (function autorun3(){
     let x3 = 3;
      
     console.log(x0 + " " + x1 + " " + x2 + " " + x3);//0 1 2 3
    })();
  })();
})();

内部函数 autorun3()  可以访问本地 x3 变量。还可以从外部函数访问变量 x1x2 和全局变量 x0

"use strict";
x = 1;
console.log(x)
//Uncaught ReferenceError: x is not defined
이렇게 하면 GLOBAL_DATA 변수가 모든 곳에 있게 됩니다.

x = 1;
console.log(x); //1
하지만 이 접근 방식이 나쁘다는 것도 알고 계시죠.

모듈 범위

모듈이 활성화되지 않은 경우 모든 함수 외부에서 선언된 변수는 전역 변수입니다. 모듈에서 함수 외부에 선언된 변수는 숨겨져 있으며 명시적으로 내보내지 않는 한 다른 모듈에서 사용할 수 없습니다.

내보내기를 통해 다른 모듈에서 함수나 개체를 사용할 수 있습니다. 이 예에서는 모듈 파일 sequence.js에서 함수를 내보냈습니다. 🎜rrreee🎜현재 모듈은 다른 모듈의 함수나 객체를 가져와서 사용할 수 있습니다. 🎜rrreee🎜어느 정도 모듈은 가져온 데이터를 입력으로 사용하고 내보낸 데이터를 반환하는 자동으로 실행되는 함수로 생각할 수 있습니다. 🎜🎜함수 범위🎜🎜함수 범위는 함수에 정의된 매개변수와 변수가 함수 내부 어디에서나 볼 수 있지만 함수 외부에서는 볼 수 없음을 의미합니다. 🎜🎜다음은 IIFE라는 자동 실행 함수입니다. 🎜rrreee🎜IIFE는 즉시 호출되는 함수 표현을 의미하며, 정의된 후 즉시 실행되는 함수입니다. 🎜🎜 var 로 선언된 변수에는 함수 범위만 있습니다. 더 중요한 것은 var로 선언된 변수가 해당 범위의 맨 위로 승격된다는 것입니다. 이렇게 하면 선언되기 전에 액세스할 수 있습니다. 다음 코드를 살펴보세요. 🎜rrreee🎜let에서는 이런 일이 발생하지 않습니다. let으로 선언된 변수는 정의된 후에만 액세스할 수 있습니다. 🎜rrreee🎜 var로 선언된 변수는 동일한 범위에서 여러 번 다시 선언될 수 있습니다. 🎜rrreee🎜 let 또는 const로 선언된 변수는 다시 선언할 수 없습니다. 같은 범위에서: 🎜rrreee🎜var가 더 이상 사용되지 않기 시작하므로 이에 대해 신경 쓰지 않아도 될 것입니다. 🎜🎜블록 범위🎜🎜블록 범위는 중괄호로 정의됩니다. {}로 구분됩니다. 🎜🎜 letconst로 선언된 변수는 블록 범위의 적용을 받을 수 있으며 해당 변수가 정의된 블록 내에서만 액세스할 수 있습니다. 🎜🎜let 블록 범위와 관련하여 다음 코드를 고려하세요. 🎜rrreee🎜반면, var 선언은 블록 범위에 바인딩되지 않습니다. 🎜rrreee🎜또 다른 일반적인 질문은 비동기 작업 사용입니다. 루프의 setTimeout()과 같습니다. 다음 루프 코드는 숫자 5를 5번 표시합니다. 🎜rrreee🎜 let 선언이 포함된 for 루프 문은 루프할 때마다 새 변수를 생성하고 이를 블록 범위로 설정합니다. 다음 코드 루프는 0 1 2 3 4 5를 표시합니다. 🎜rrreee🎜 어휘 범위 🎜🎜 어휘 범위는 자신을 정의하는 외부 범위에 액세스할 수 있는 내부 함수의 기능입니다. 🎜🎜이 코드를 보세요: 🎜rrreee🎜log 함수는 클로저입니다. run()x 변수가 아니라 상위 함수 autorun()x 변수를 참조합니다. 기능. 🎜🎜클로저 함수는 자체 범위가 아닌 생성된 범위에 액세스할 수 있습니다. 🎜🎜autorun()의 로컬 함수 범위는 log() 함수의 어휘 범위입니다. 🎜🎜Scope Chain🎜🎜모든 범위에는 상위 범위에 대한 링크가 있습니다. 변수를 사용할 때 JavaScript는 요청된 변수를 찾거나 전역 범위(즉, 범위 체인의 끝)에 도달할 때까지 범위 체인을 살펴봅니다.
다음 예를 보세요: 🎜rrreee🎜내부 함수 autorun3()는 로컬 x3 변수에 액세스할 수 있습니다. x1x2 변수와 전역 변수 x0는 외부 함수에서도 액세스할 수 있습니다. 🎜🎜변수를 찾을 수 없으면 엄격 모드에서 오류를 반환합니다. 🎜rrreee🎜비엄격 모드는 "sloppy 모드"라고도 하는데, 전역 변수를 성급하게 생성하는 모드입니다. 🎜rrreee🎜Summary🎜🎜전역 범위에 정의된 변수는 프로그램의 어느 곳에서나 사용할 수 있습니다. 🎜

모듈에서는 함수 외부에 선언된 변수가 숨겨져 있어 명시적으로 내보내지 않는 한 다른 모듈에서 사용할 수 없습니다.

함수 범위는 함수에 정의된 매개변수와 변수가 함수 내 어디에서나 볼 수 있음을 의미합니다.

letconst 声明的变量具有块作用域。 var에는 블록 범위가 없습니다.

【관련 추천: JavaScript 비디오 튜토리얼

위 내용은 JavaScript 범위에 대한 종합 분석(코드 포함)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제