목차
天下苦 CommonJs 久矣
export 和 import
🎜天下狠 CommonJs 久矣🎜
🎜export 및 import🎜
在浏览器中使用 Es Module
模块的默认延迟
Es Module 和 Commonjs 的区别
Es Module 工作原理的相关概念
Es Module 的解析流程
ImportEntry Records
Es 모듈 구문 분석 프로세스
ImportEntry 레코드
ExportEntry Records
Es module 是如何解决循环引用的
Es 모듈이 순환 참조를 해결하는 방법
웹 프론트엔드 JS 튜토리얼 es6의 모듈성을 자세히 설명하는 기사

es6의 모듈성을 자세히 설명하는 기사

Nov 02, 2022 pm 08:17 PM
javascript es6 프런트 엔드 회견

es6의 모듈성을 자세히 설명하는 기사

CommonJs에는 뛰어난 기능이 많이 있습니다. 아래에서 간단히 살펴보겠습니다. CommonJs 有很多优秀的特性,下面我们再简单的回顾一下:

  • 模块代码只在加载后运行;

  • 模块只能加载一次;

  • 模块可以请求加载其他模块;

  • 支持循环依赖;

  • 模块可以定义公共接口,其他模块可以基于这个公共接口观察和交互;

天下苦 CommonJs 久矣


Es Module 的独特之处在于,既可以通过浏览器原生加载,也可以与第三方加载器和构建工具一起加载。

支持 Es module 模块的浏览器可以从顶级模块加载整个依赖图,且是异步完成。浏览器会解析入口模块,确定依赖,并发送对依赖模块的请求。这些文件通过网络返回后,浏览器就会解析它们的依赖,,如果这些二级依赖还没有加载,则会发送更多请求。

这个异步递归加载过程会持续到整个应用程序的依赖图都解析完成。解析完成依赖图,引用程序就可以正式加载模块了。

Es Module 不仅借用了 CommonJsAMD 的很多优秀特性,还增加了一些新行为:

  • Es Module 默认在严格模式下执行;

  • Es Module 不共享全局命名空;

  • Es Module 顶级的 this 的值是 undefined(常规脚本是window);

  • 模块中的 var 声明不会添加到 window 对象;

  • Es Module 是异步加载和执行的;

export 和 import


  • 模块功能主要由两个命令构成: exportsimport

  • export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。

export的基本使用

  • 导出的基本形式:
export const nickname = "moment";
export const address = "广州";
export const age = 18;
로그인 후 복사
  • 当然了,你也可以写成以下的形式:
const nickname = "moment";
const address = "广州";
const age = 18;

export { nickname, address, age };
로그인 후 복사
  • 对外导出一个对象和函数
export function foo(x, y) {
  return x + y;
}

export const obj = {
  nickname: "moment",
  address: "广州",
  age: 18,
};

// 也可以写成这样的方式
function foo(x, y) {
  return x + y;
}

const obj = {
  nickname: "moment",
  address: "广州",
  age: 18,
};

export { foo, obj };
로그인 후 복사
  • 通常情况下,export输出的变量就是本来的名字,但是可以使用as关键字重命名。
const address = "广州";
const age = 18;

export { nickname as name, address as where, age as old };
로그인 후 복사
  • 默认导出,值得注意的是,一个模块只能有一个默认导出:
export default "foo";

export default { name: 'moment' }

export default function foo(x,y) {
  return x+y
}

export { bar, foo as default };
로그인 후 복사

export 的错误使用

  • 导出语句必须在模块顶级,不能嵌套在某个块中:
if(true){
export {...};
}
로그인 후 복사
  • export 必须提供对外的接口:
// 1只是一个值,不是一个接口
export 1

// moment只是一个值为1的变量
const moment = 1
export moment

// function和class的输出,也必须遵守这样的写法
function foo(x, y) {
    return x+y
}
export foo
로그인 후 복사

import的基本使用

  • 使用 export 命令定义了模块的对外接口以后,其他js文件就可以通过 import 命令加载整个模块
import {foo,age,nickname} form '模块标识符'
로그인 후 복사
  • 模块标识符可以是当前模块的相对路径,也可以是绝对路径,也可以是纯字符串,但不能是动态计算的结果,例如凭借的字符串。
  • import 命令后面接受一个花括弧,里面指定要从其他模块导入的变量名,而且变量名必须与被导入模块的对外接口的名称相同。
  • 对于导入的变量不能对其重新赋值,因为它是一个只读接口,如果是一个对象,可以对这个对象的属性重新赋值。导出的模块可以修改值,导入的变量也会跟着改变。

es6의 모듈성을 자세히 설명하는 기사

  • 从上图可以看得出来,对象的属性被重新赋值了,而变量的则报了 Assignment to constant variable 的类型错误。
  • 如果模块同时导出了命名导出和默认导出,则可以在 import 语句中同时取得它们。可以依次列出特定的标识符来取得,也可以使用 * 来取得:
// foo.js
export default function foo(x, y) {
  return x + y;
}

export const bar = 777;

export const baz = "moment";

// main.js
import { default as foo, bar, baz } from "./foo.js";

import foo, { bar, baz } from "./foo.js";

import foo, * as FOO from "./foo.js";
로그인 후 복사

动态 import

  • 标准用法的 import 导入的模块是静态的,会使所有被导入的模块,在加载时就被编译(无法做到按需编译,降低首页加载速度)。有些场景中,你可能希望根据条件导入模块或者按需导入模块,这时你可以使用动态导入代替静态导入。
  • 关键字 import 可以像调用函数一样来动态的导入模块。以这种方式调用,将返回一个 promise
    • 모듈 코드는 Run에만 있습니다. 로드 후;

  • 모듈은 한 번만 로드할 수 있습니다.
  • 모듈은 다른 모듈을 로드하도록 요청할 수 있습니다.

    🎜
  • 🎜순환 종속성을 지원합니다.🎜🎜
  • 🎜모듈은 공개를 정의할 수 있습니다. 인터페이스를 사용하면 다른 모듈이 이 공개 인터페이스를 기반으로 관찰하고 상호 작용할 수 있습니다. 🎜🎜🎜

    🎜天下狠 CommonJs 久矣🎜


    🎜Es 모듈은 두 가지 모두에서 고유합니다. 브라우저나 타사 로더 및 빌드 도구를 통해 기본적으로 로드할 수 있습니다. 🎜🎜Es 모듈 모듈을 지원하는 브라우저는 최상위 모듈에서 전체 종속성 그래프를 비동기적으로 로드할 수 있습니다. 브라우저는 항목 모듈을 구문 분석하고, 종속성을 결정하고, 종속 모듈에 대한 요청을 보냅니다. 이러한 파일이 네트워크를 통해 반환된 후 브라우저는 해당 종속성을 해결하고 이러한 보조 종속성이 로드되지 않은 경우 추가 요청이 전송됩니다. 🎜🎜이 비동기 재귀 로딩 프로세스는 전체 애플리케이션의 종속성 그래프가 해결될 때까지 계속됩니다. 종속성 그래프가 구문 분석된 후 참조 프로그램은 공식적으로 모듈을 로드할 수 있습니다. 🎜🎜Es 모듈CommonJsAMD의 많은 뛰어난 기능을 빌릴 뿐만 아니라 몇 가지 새로운 동작도 추가합니다. 🎜
    • 🎜Es 모듈은 기본적으로 엄격 모드에서 실행됩니다. 🎜🎜
    • 🎜Es 모듈은 전역을 공유하지 않습니다. 🎜🎜
    • 🎜Es 모듈 최상위 this의 값은 정의되지 않았습니다(일반 스크립트는 window</code)입니다. code>); 🎜🎜<li>🎜모듈의 <code>var 선언은 window 객체에 추가되지 않습니다. 🎜🎜
    • 🎜Es 모듈 는 비동기적으로 로드되어 실행됩니다.🎜🎜🎜

      🎜export 및 import🎜


      • 🎜모듈 기능은 주로 두 가지 명령으로 구성됩니다: exports< /code> 및 <code >가져오기. 🎜🎜
      • export 명령은 모듈의 외부 인터페이스를 지정하는 데 사용되며, import 명령은 다른 모듈에서 제공하는 기능을 가져오는 데 사용됩니다. 🎜🎜🎜🎜🎜export의 기본 사용법🎜🎜🎜
        • 기본 내보내기 형식: 🎜🎜
          import("./foo.js").then((module) => {
            const { default: foo, bar, baz } = module;
            console.log(foo); // [Function: foo]
            console.log(bar); // 777
            console.log(baz); // moment
          });
          로그인 후 복사
          • 물론 다음 형식으로도 작성할 수도 있습니다. 🎜🎜
            const p = new Promise((resolve, reject) => {
              resolve(111);
            });
            
            // SyntaxError: await is only valid in async functions and the top level bodies of modules
            const result = await p;
            
            console.log(result);
            로그인 후 복사
            로그인 후 복사
              < li>객체와 함수를 외부로 내보내기 🎜🎜
              const p = new Promise((resolve, reject) => {
                resolve(777);
              });
              
              const result = await p;
              
              console.log(result); // 777正常输出
              로그인 후 복사
              로그인 후 복사
              • 보통 export로 출력되는 변수는 원래 이름이지만 를<로 사용할 수 있습니다. /code> 키워드 이름을 바꿉니다. 🎜🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>// 错误 import { &amp;#39;b&amp;#39; + &amp;#39;ar&amp;#39; } from &amp;#39;./foo.js&amp;#39;; // 错误 let module = &amp;#39;./foo.js&amp;#39;; import { bar } from module; // 错误 if (x === 1) { import { bar } from &amp;#39;./foo.js&amp;#39;; } else { import { foo } from &amp;#39;./foo.js&amp;#39;; }</pre><div class="contentsignin">로그인 후 복사</div></div><div class="contentsignin">로그인 후 복사</div></div><ul><li>기본 내보내기, 모듈에는 하나의 기본 내보내기만 있을 수 있다는 점에 유의할 가치가 있습니다: 🎜🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>&lt;script type=&quot;module&quot; src=&quot;./main.mjs&quot;&gt;&lt;/script&gt; &lt;script type=&quot;module&quot;&gt;&lt;/script&gt;</pre><div class="contentsignin">로그인 후 복사</div></div><div class="contentsignin">로그인 후 복사</div></div>🎜🎜🎜export 잘못된 사용🎜🎜🎜<ul><li>내보내기 문은 다음 위치에 있어야 합니다. 모듈 최상위 수준, 블록에 중첩될 수 없음: 🎜🎜<div class="code" style="position:relative; padding:0px; margin:0px;"><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'> &lt;script type=&quot;module&quot;&gt; console.log(&quot;模块情况下的&quot;); &lt;/script&gt; &lt;script src=&quot;./main.js&quot; type=&quot;module&quot; defer&gt;&lt;/script&gt; &lt;script&gt; console.log(&quot;正常 script标签&quot;); &lt;/script&gt;</pre><div class="contentsignin">로그인 후 복사</div></div><div class="contentsignin">로그인 후 복사</div></div><ul><li><code>export 외부 인터페이스를 제공해야 함: 🎜🎜
                    <script src="./foo.js"></script>
                    <script src="./foo.js"></script>
                
                    <script type="module" src="./main.js"></script>
                    <script type="module" src="./main.js"></script>
                    <script type="module" src="./main.js"></script>
                로그인 후 복사
                로그인 후 복사
                🎜🎜🎜import의 기본 사용🎜🎜🎜
                • export 명령을 사용하여 모듈의 외부 인터페이스를 정의한 후 다른 js 파일에서 import 명령을 통해 전체 모듈을 로드할 수 있습니다🎜🎜
                  // main.js
                  import { bar } from "./bar.js";
                  export const main = "main";
                  console.log("main");
                  
                  // foo.js
                  import { main } from "./main.js";
                  export const foo = "foo";
                  console.log("foo");
                  
                  // bar.js
                  import { foo } from "./foo.js";
                  export const bar = "bar";
                  console.log("bar");
                  로그인 후 복사
                  로그인 후 복사
                  • 모듈 식별 문자는 현재 모듈에 대한 상대 경로, 절대 경로 또는 순수 문자열일 수 있지만 종속 문자열과 같은 동적 계산의 결과일 수는 없습니다. 🎜
                  • import 이 명령은 다른 모듈에서 가져올 변수 이름을 지정하는 중괄호를 허용하며, 변수 이름은 가져온 모듈의 외부 인터페이스 이름과 동일해야 합니다. . 🎜
                  • 가져온 변수는 읽기 전용 인터페이스이므로 재할당할 수 없습니다. 객체인 경우 해당 객체의 속성을 재할당할 수 있습니다. 내보낸 모듈은 값을 수정할 수 있으며 가져온 변수도 이에 따라 변경됩니다. 🎜🎜🎜es6의 모듈성을 자세히 설명하는 기사🎜
                    • 위 그림에서 볼 수 있듯이 객체의 속성이 재할당된 반면, 변수에서는 상수 변수에 할당</code'이라는 유형 오류가 보고되었습니다. >. 🎜<li>모듈이 명명된 내보내기와 기본 내보내기를 모두 내보내는 경우 <code>import 문에서 동시에 가져올 수 있습니다. 이를 얻기 위해 특정 식별자를 나열하거나 *를 사용하여 얻을 수 있습니다. 🎜🎜rrreee🎜🎜🎜dynamic import🎜🎜🎜
                      • 의 표준 사용법 import< /code> 가져온 모듈은 정적이므로 가져온 모든 모듈이 로드될 때 컴파일됩니다(요청 시 컴파일을 수행할 수 없으므로 홈 페이지의 로드 속도가 느려집니다). 일부 시나리오에서는 조건이나 요청 시 모듈을 가져올 수 있습니다. 이 경우 정적 가져오기 대신 동적 가져오기를 사용할 수 있습니다. 🎜<li><code>import 키워드는 함수를 호출하는 것처럼 모듈을 동적으로 가져올 수 있습니다. 이런 식으로 호출하면 promise가 반환됩니다. 🎜🎜rrreee🎜🎜🎜최상위 대기 사용🎜🎜🎜
                        • 在经典脚本中使用 await 必须在带有 async 的异步函数中使用,否则会报错:
                        const p = new Promise((resolve, reject) => {
                          resolve(111);
                        });
                        
                        // SyntaxError: await is only valid in async functions and the top level bodies of modules
                        const result = await p;
                        
                        console.log(result);
                        로그인 후 복사
                        로그인 후 복사
                        • 而在模块中,你可以直接使用 Top-level await:
                        const p = new Promise((resolve, reject) => {
                          resolve(777);
                        });
                        
                        const result = await p;
                        
                        console.log(result); // 777正常输出
                        로그인 후 복사
                        로그인 후 복사

                        import 的错误使用

                        • 由于import是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。
                        // 错误
                        import { &#39;b&#39; + &#39;ar&#39; } from &#39;./foo.js&#39;;
                        
                        // 错误
                        let module = &#39;./foo.js&#39;;
                        import { bar } from module;
                        
                        // 错误
                        if (x === 1) {
                          import { bar } from &#39;./foo.js&#39;;
                        } else {
                          import { foo } from &#39;./foo.js&#39;;
                        }
                        로그인 후 복사
                        로그인 후 복사

                        在浏览器中使用 Es Module


                        • 在浏览器上,你可以通过将 type 属性设置为 module 用来告知浏览器将 script 标签视为模块。

                        <script type="module" src="./main.mjs"></script>
                        <script type="module"></script>
                        로그인 후 복사
                        로그인 후 복사
                        • 模块默认情况下是延迟的,因此你还可以使用 defer 的方式延迟你的 nomodule 脚本:
                          <script type="module">
                              console.log("模块情况下的");
                            </script>
                            <script src="./main.js" type="module" defer></script>
                            <script>
                              console.log("正常 script标签");
                            </script>
                        로그인 후 복사
                        로그인 후 복사

                        es6의 모듈성을 자세히 설명하는 기사

                        • 在浏览器中,引入相同的 nomodule 脚本会被执行多次,而模块只会被执行一次:
                            <script src="./foo.js"></script>
                            <script src="./foo.js"></script>
                        
                            <script type="module" src="./main.js"></script>
                            <script type="module" src="./main.js"></script>
                            <script type="module" src="./main.js"></script>
                        로그인 후 복사
                        로그인 후 복사

                        es6의 모듈성을 자세히 설명하는 기사

                        模块的默认延迟


                        • 默认情况下,nomodule 脚本会阻塞 HTML 解析。你可以通过添加 defer 属性来解决此问题,该属性是等到 HTML 解析完成之后才执行。

                        es6의 모듈성을 자세히 설명하는 기사

                        • deferasync 是一个可选属性,他们只可以选择其中一个,在 nomodule 脚本下,defer 等到 HTML 解析完才会解析当前脚本,而 async 会和 HTML 并行解析,不会阻塞 HTML 的解析,模块脚本可以指定 async 属性,但对于 defer 无效,因为模块默认就是延迟的。
                        • 对于模块脚本,如果存在 async 属性,模块脚本及其所有依赖项将于解析并行获取,并且模块脚本将在它可用时进行立即执行。

                        Es Module 和 Commonjs 的区别


                        讨论 Es Module 模块之前,必须先了解 Es ModuleCommonjs 完全不同,它们有三个完全不同:

                        • CommonJS 模块输出的是一个值的拷贝,Es Module 输出的是值的引用;

                        • CommonJS 模块是运行时加载,Es Module 是编译时输出接口。

                        • CommonJS 模块的 require() 是同步加载模块,ES6 模块的import命令是异步加载,有一个独立的模块依赖的解析阶段。

                        第二个差异是因为 CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 Es Module 不是对象,它的对外接口只是一种静态定义,在代码静态解析阶段就会生成。

                        Commonjs 输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。具体可以看上一篇写的文章。

                        Es Module 的运行机制与 CommonJS 不一样。JS引擎 对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,import就是一个连接管道,原始值变了,import 加载的值也会跟着变。因此,Es Module 是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。

                        Es Module 工作原理的相关概念


                        • 在学习工作原理之前,我们不妨来认识一下相关的概念。

                        Module Record

                        模块记录(Module Record) 封装了关于单个模块(当前模块)的导入和导出的结构信息。此信息用于链接连接模块集的导入和导出。一个模块记录包括四个字段,它们只在执行模块时使用。其中这四个字段分别是:

                        • Realm: 创建当前模块的作用域;

                        • Environment:模块的顶层绑定的环境记录,该字段在模块被链接时设置;

                        • 네임스페이스: 모듈 네임스페이스 개체는 모듈 내보내기 바인딩에 대한 런타임 속성 기반 액세스를 제공하는 모듈 네임스페이스 외부 개체입니다. 모듈 네임스페이스 객체에는 생성자가 없습니다.

                          Namespace:模块命名空间对象是模块命名空间外来对象,它提供对模块导出绑定的基于运行时属性的访问。模块命名空间对象没有构造函数;

                        • HostDefined:字段保留,以按 host environments 使用,需要将附加信息与模块关联。

                        Module Environment Record

                        • 模块环境记录是一种声明性环境记录,用于表示ECMAScript模块的外部作用域。除了普通的可变和不可变绑定之外,模块环境记录还提供了不可变的 import 绑定,这些绑定提供了对存在于另一个环境记录中的目标绑定的间接访问。

                        不可变绑定就是当前的模块引入其他的模块,引入的变量不能修改,这就是模块独特的不可变绑定。

                        Es Module 的解析流程


                        在开始之前,我们先大概了解一下整个流程大概是怎么样的,先有一个大概的了解:

                        • 阶段一:构建(Construction),根据地址查找 js 文件,通过网络下载,并且解析模块文件为 Module Record;

                        • 阶段二:实例化(Instantiation),对模块进行实例化,并且分配内存空间,解析模块的导入和导出语句,把模块指向对应的内存地址;

                        • 阶段三:运行(Evaluation),运行代码,计算值,并且将值填充到内存地址中;

                        Construction 构建阶段

                        • loader 负责对模块进行寻址及下载。首先我们修改一个入口文件,这在 HTML 中通常是一个 <script type="module"></script> 的标签来表示一个模块文件。

                        es6의 모듈성을 자세히 설명하는 기사

                        • 模块继续通过 import语句声明,在 import声明语句中有一个 模块声明标识符(ModuleSpecifier),这告诉 loader 怎么查找下一个模块的地址。

                        es6의 모듈성을 자세히 설명하는 기사

                        • 每一个模块标识号对应一个 模块记录(Module Record),而每一个 模块记录 包含了 JavaScript代码执行上下文ImportEntriesLocalExportEntriesIndirectExportEntriesStarExportEntries。其中 ImportEntries 值是一个 ImportEntry Records 类型,而 LocalExportEntriesIndirectExportEntriesStarExportEntries 是一个 ExportEntry Records 类型。

                        ImportEntry Records

                        • 一个 ImportEntry Records 包含三个字段 ModuleRequestImportNameLocalName;

                        ModuleRequest: 一个模块标识符(ModuleSpecifier);

                        ImportName: 由 ModuleRequest 模块标识符的模块导出所需绑定的名称。值 namespace-object 表示导入请求是针对目标模块的命名空间对象的;

                        LocalName: 用于从导入模块中从当前模块中访问导入值的变量;

                        • 详情可参考下图:es6의 모듈성을 자세히 설명하는 기사
                        • 下面这张表记录了使用 import 导入的 ImportEntry Records
                        HostDefined: 호스트 환경에서 사용하도록 예약된 필드입니다. 모듈과 연결하려면 추가 정보가 필요합니다.

                        모듈 환경 기록

                          불변 바인딩은 현재 모듈이 다른 모듈을 도입하고, 도입된 변수를 수정할 수 없다는 것을 의미합니다. 이는 모듈의 고유한 불변 바인딩입니다.

                          Es 모듈 구문 분석 프로세스


                          2단계: 인스턴스화(인스턴스화 code>) , 모듈을 인스턴스화하고, 메모리 공간을 할당하고, 모듈의 가져오기 및 내보내기 문을 구문 분석하고, 모듈을 해당 메모리 주소로 지정합니다.

                          구성 구성 단계< /p>
                            es6의 모듈성을 자세히 설명하는 기사
                              모듈은 import 문을 통해 계속 선언됩니다. import에 모듈 선언 식별자(ModuleSpecifier)가 있습니다. 이 문장은 loader에게 다음 모듈의 주소를 찾는 방법을 알려줍니다. es6의 모듈성을 자세히 설명하는 기사
                                A ImportEntry Records에는 ModuleRequest< / code>, <code>ImportName, LocalName;ModuleRequest: 모듈 식별자(ModuleSpecifier);

                                ImportName: ModuleRequest 모듈 식별자의 모듈 내보내기에 필요한 바인딩 이름입니다. namespace-object 값은 가져오기 요청이 대상 모듈의 네임스페이스 개체에 대한 것임을 나타냅니다.

                                자세한 내용은 아래 사진을 참고해주세요:es6의 모듈성을 자세히 설명하는 기사다음 표에는 import를 사용하여 가져온 ImportEntry Records 필드의 인스턴스가 기록되어 있습니다. Import 문 양식)모듈 식별자(ModuleRequest)가져오기 이름(ImportName)로컬 이름(LocalName)
                                모듈 환경 기록은 선언적 환경 기록입니다. ECMAScript 모듈의 외부 범위를 나타내는 데 사용됩니다. 일반적인 변경 가능 및 불변 바인딩 외에도 모듈 환경 레코드는 다른 환경 레코드 간접 액세스에 존재하는 대상에 대한 바인딩을 제공하는 변경 불가능한 import 바인딩도 제공합니다.
                                시작하기 전에 전체 프로세스가 어떻게 생겼는지 대략적으로 살펴보겠습니다. 일반적인 이해:

                                  1단계: 건설(건설), 주소에 따라 검색 < code>js 파일을 인터넷을 통해 다운로드하고 모듈 파일을 모듈 레코드로 구문 분석합니다.

                                  3단계: 실행(평가 code>), 코드를 실행하고, 값을 계산하고, 그 값을 메모리 주소에 채웁니다;

                                  loader는 모듈 주소 지정 및 다운로드를 담당합니다. 먼저 HTML에서 일반적으로 모듈 파일을 나타내는 <script type="module"></script> 태그인 항목 파일을 수정합니다.
                                  각 모듈 식별 번호는 모듈 레코드에 해당하며 각 모듈 레코드에는 JavaScript 코드, 실행 컨텍스트가 포함되어 있습니다. , ImportEntries, LocalExportEntries, IndirectExportEntries, StarExportEntries. ImportEntries 값은 ImportEntry Records 유형이고 LocalExportEntries, IndirectExportEntries, StarExportEntries ExportEntry Records 유형입니다.

                                  ImportEntry 레코드

                                    LocalName: 가져온 모듈에서 현재 모듈의 가져온 값에 액세스하는 데 사용되는 변수입니다.

                                      🎜import React from "react";🎜🎜"react"🎜🎜"default"🎜🎜"React "🎜🎜🎜🎜import * as Moment from "react";🎜🎜"react"🎜🎜namespace-obj🎜🎜"Moment"🎜🎜🎜🎜import {useEffect} from "react";🎜🎜"react"🎜🎜" useEffect"🎜🎜"useEffect"🎜🎜🎜🎜import {useEffect as effect } from "react";🎜🎜"react"🎜🎜"useEffect"🎜🎜"효과"🎜🎜🎜🎜

                                      ExportEntry Records

                                      • ExportEntry Records에는 ExportName, ModuleRequest, ImportName, < ImportEntry Records와 다른 code>LocalName에는 추가 ExportName이 있습니다.

                                      ExportName: 내보낼 때 이 모듈이 바인딩하는 데 사용하는 이름입니다. ExportEntry Records 包含四个字段 ExportNameModuleRequestImportNameLocalName,和 ImportEntry Records不同的是多了一个 ExportName

                                    ExportName: 此模块用于导出时绑定的名称。

                                    • 下面这张表记录了使用 export 导出的 ExportEntry Records

                                      다음 표에는 내보내기를 사용하여 내보낸 ExportEntry 레코드 필드의 인스턴스가 기록되어 있습니다.

                                      로컬 이름"v""f"default"default""x""v"nullnullnullnull
                                      내보내기 선언내보내기 이름모듈 식별자 가져오기 이름
                                      export var v;"v"nullnull
                                      내보내기 기본 함수 f() {} "기본값" nullnull
                                      기본 기능 내보내기() {}"default"nullnull"
                                      기본값 42 내보내기 ; "default"nullnull"
                                      export {x};"x"nullnull
                                      {v를 x로 내보내기 };"x"nullnull
                                      "mod"에서 {x} 내보내기;"x""mod""x"
                                      "mod"에서 {v를 x로 내보내기;"x""mod""v"
                                      export * from "mod";null "mod "all-but-default
                                      "mod"에서 ns로 * 내보내기;"ns"mod"all
                                      🎜🎜
                                    • 주제로 돌아가기

                                    • 현재 모듈 레코드를 구문 분석한 후에만 현재 모듈이 어떤 하위 모듈에 의존하는지 알 수 있으며 그런 다음 하위 해결이 필요합니다. 모듈, 하위 모듈을 얻은 다음 하위 모듈을 구문 분석하고 이 해결 프로세스를 계속해서 가져오고 분석합니다. 결과는 아래 그림과 같습니다. Module Record 之后,才能知道当前模块依赖的是那些子模块,然后你需要 resolve 子模块,获取子模块,再解析子模块,不断的循环这个流程 resolving -> fetching -> parsing,结果如下图所示:

                                    es6의 모듈성을 자세히 설명하는 기사

                                    • 这个过程也称为 静态分析,不会运行JavaScript代码,只会识别 exportimport 关键字,所以说不能在非全局作用域下使用 import,动态导入除外。
                                    • 如果多个文件同时依赖一个文件呢,这会不会引起死循环,答案是不会的。
                                    • loader 使用 Module Map 对全局的 MOdule Record 进行追踪、缓存这样就可以保证模块只被 fetch 一次,每个全局作用域中会有一个独立的 Module Map。

                                    MOdule Map 是由一个 URL 记录和一个字符串组成的key/value的映射对象。URL记录是获取模块的请求URL,字符串指示模块的类型(例如。“javascript”)。模块映射的值要么是模块脚本,null(用于表示失败的获取),要么是占位符值“fetching(获取中)”。

                                    es6의 모듈성을 자세히 설명하는 기사

                                    linking 链接阶段

                                    • 在所有 Module Record 被解析完后,接下来 JS 引擎需要把所有模块进行链接。JS 引擎以入口文件的 Module Record 作为起点,以深度优先的顺序去递归链接模块,为每个 Module Record 创建一个 Module Environment Record,用于管理 Module Record 中的变量。

                                    es6의 모듈성을 자세히 설명하는 기사

                                    • Module Environment Record 中有一个 Binding,这个是用来存放 Module Record 导出的变量,如上图所示,在该模块 main.js 处导出了一个 count 的变量,在 Module Environment Record 中的 Binding 就会有一个 count,在这个时候,就相当于 V8 的编译阶段,创建一个模块实例对象,添加相对应的属性和方法,此时值为 undefined 或者 null,为其分配内存空间。
                                    • 而在子模块 count.js 中使用了 import 关键字对 main.js 进行导入,而 count.jsimportmain.jsexport 的变量指向的内存位置是一致的,这样就把父子模块之间的关系链接起来了。如下图所示:

                                    es6의 모듈성을 자세히 설명하는 기사

                                    • 需要注意的是,我们称 export 导出的为父模块,import 引入的为子模块,父模块可以对变量进行修改,具有读写权限,而子模块只有读权限。

                                    Evaluation 求值阶段

                                    • 在模块彼此链接完之后,执行对应模块文件中顶层作用域的代码,确定链接阶段中定义变量的值,放入内存中。

                                    Es module 是如何解决循环引用的


                                    • Es Module 中有5种状态,分别为 unlinkedlinkinglinkedevaluatingevaluated,用循环模块记录(Cyclic Module Records)的 Status 字段来表示,正是通过这个字段来判断模块是否被执行过,每个模块只执行一次。这也是为什么会使用 Module Map 来进行全局缓存 Module Record 的原因了,如果一个模块的状态为 evaluated,那么下次执行则会自动跳过,从而包装一个模块只会执行一次。 Es Module 采用 深度优先

                                    🎜es6의 모듈성을 자세히 설명하는 기사🎜
                                      🎜이 프로세스 정적 분석이라고도 하며 JavaScript 코드를 실행하지 않으며 내보내기가져오기 키워드만 인식하므로 가져오기</ 코드는 동적 가져오기를 제외하고 비전역 범위에서 사용할 수 없습니다. 🎜🎜여러 파일이 동시에 하나의 파일에 의존하는 경우 무한 루프가 발생합니까? 대답은 '아니요'입니다. 🎜🎜<code>loader모듈 맵을 사용하여 전역 MOdule 레코드를 추적하고 캐시하여 모듈이 가져오기 >만 수행되도록 합니다. 일단 각 전역 범위에 독립적인 모듈 맵이 있게 됩니다. 🎜
                                    🎜MOdule Map은 URL 레코드와 문자열로 구성된 키/값 매핑 개체입니다. URL 레코드는 모듈을 가져오기 위한 요청 URL이며, 모듈 유형을 나타내는 문자열(예: "javascript")입니다. 모듈 맵의 값은 모듈 스크립트, null(가져오기 실패를 나타내는 데 사용됨) 또는 자리 표시자 값 "가져오기"입니다. 🎜
                                    🎜es6의 모듈성을 자세히 설명하는 기사🎜🎜링크 연결 단계🎜
                                      🎜모든 모듈 레코드가 구문 분석된 후, 그런 다음 JS 엔진은 모든 모듈을 연결해야 합니다. JS 엔진은 항목 파일의 모듈 레코드를 시작점으로 사용하여 깊이 우선 순서로 모듈을 재귀적으로 연결하고 각 모듈에 대한 <code>모듈 환경 레코드를 생성합니다. 레코드.code>, 모듈 레코드에서 변수를 관리하는 데 사용됩니다. 🎜
                                    🎜es6의 모듈성을 자세히 설명하는 기사🎜
                                      🎜모듈 환경 레코드에는 그림과 같이 모듈 레코드에서 내보낸 변수를 저장하는 데 사용되는 바인딩이 있습니다. 위의 경우 count 변수는 이 모듈의 main.js로 내보내지고 모듈 환경 레코드Binding count가 있을 것입니다. 이때는 V8의 컴파일 단계와 동일하며, 모듈 인스턴스 객체를 생성하고 해당 속성과 메서드를 추가합니다. 이번에는 정의되지 않음 또는 null이므로 메모리 공간을 할당하세요. 🎜🎜import 키워드는 하위 모듈 count.js에서 main.js를 가져오는 데 사용되며 count.js는 import 변수와 main.jsexport 변수가 가리키는 메모리 위치가 동일하므로 상위 및 하위 모듈 관계가 연결됩니다. 아래 그림과 같이: 🎜
                                    🎜es6의 모듈성을 자세히 설명하는 기사 🎜
                                      🎜 export가 내보내는 것을 상위 모듈이라고 부르고, import가 소개하는 것을 하위 모듈이라고 부릅니다. 상위 모듈은 읽기 및 쓰기 권한으로 변수를 수정할 수 있지만 하위 모듈은 읽기 권한만 갖습니다. 🎜
                                    🎜평가 평가 단계🎜
                                      🎜모듈이 서로 연결된 후 해당 모듈을 실행합니다. 모듈 파일 최상위 범위의 코드는 링크 단계에서 정의된 변수의 값을 결정하고 이를 메모리에 저장합니다. 🎜

                                    Es 모듈이 순환 참조를 해결하는 방법


                                      🎜🎜 Es 모듈 상태에는 5가지 유형이 있습니다. 각각 연결 해제, 연결, 연결, 평가평가를 사용하여 표현됩니다. 순환 모듈 레코드(Cyclic Module Records)의 상태 필드를 통해 각 모듈이 한 번만 실행되었는지 판단합니다. . 이것이 모듈 맵모듈 레코드를 전역적으로 캐시하는 데 사용되는 이유이기도 합니다. 모듈의 상태가 evaluated이면 다음 실행이 수행됩니다. 자동으로 건너뛰므로 모듈 패키징은 한 번만 실행됩니다. Es 모듈깊이 우선 방법을 사용하여 모듈 그래프를 탐색합니다. 각 모듈은 한 번만 실행되므로 무한 루프를 방지합니다. 🎜

                                    深度优先搜索算法(英语:Depth-First-Search,DFS)是一种用于遍历或搜索树或图的算法。这个算法会尽可能深地搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。

                                    es6의 모듈성을 자세히 설명하는 기사

                                    • 看下面的例子,所有的模块只会运行一次:
                                    // main.js
                                    import { bar } from "./bar.js";
                                    export const main = "main";
                                    console.log("main");
                                    
                                    // foo.js
                                    import { main } from "./main.js";
                                    export const foo = "foo";
                                    console.log("foo");
                                    
                                    // bar.js
                                    import { foo } from "./foo.js";
                                    export const bar = "bar";
                                    console.log("bar");
                                    로그인 후 복사
                                    로그인 후 복사
                                    • 通过 node 运行 main.js ,得出以下结果:

                                    es6의 모듈성을 자세히 설명하는 기사

                                    • 好了,这篇文章到这也就结束了。

                                    原文地址:https://juejin.cn/post/7166046272300777508

                                    【推荐学习:javascript高级教程

                                    위 내용은 es6의 모듈성을 자세히 설명하는 기사의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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

                핫 AI 도구

                Undresser.AI Undress

                Undresser.AI Undress

                사실적인 누드 사진을 만들기 위한 AI 기반 앱

                AI Clothes Remover

                AI Clothes Remover

                사진에서 옷을 제거하는 온라인 AI 도구입니다.

                Undress AI Tool

                Undress AI Tool

                무료로 이미지를 벗다

                Clothoff.io

                Clothoff.io

                AI 옷 제거제

                AI Hentai Generator

                AI Hentai Generator

                AI Hentai를 무료로 생성하십시오.

                인기 기사

                R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
                3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
                R.E.P.O. 최고의 그래픽 설정
                3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
                R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
                3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

                뜨거운 도구

                메모장++7.3.1

                메모장++7.3.1

                사용하기 쉬운 무료 코드 편집기

                SublimeText3 중국어 버전

                SublimeText3 중국어 버전

                중국어 버전, 사용하기 매우 쉽습니다.

                스튜디오 13.0.1 보내기

                스튜디오 13.0.1 보내기

                강력한 PHP 통합 개발 환경

                드림위버 CS6

                드림위버 CS6

                시각적 웹 개발 도구

                SublimeText3 Mac 버전

                SublimeText3 Mac 버전

                신 수준의 코드 편집 소프트웨어(SublimeText3)

                PHP와 Vue: 프런트엔드 개발 도구의 완벽한 조합 PHP와 Vue: 프런트엔드 개발 도구의 완벽한 조합 Mar 16, 2024 pm 12:09 PM

                PHP와 Vue: 프론트엔드 개발 도구의 완벽한 조합 오늘날 인터넷이 빠르게 발전하는 시대에 프론트엔드 개발은 점점 더 중요해지고 있습니다. 사용자가 웹 사이트 및 애플리케이션 경험에 대한 요구 사항이 점점 더 높아짐에 따라 프런트 엔드 개발자는 보다 효율적이고 유연한 도구를 사용하여 반응형 및 대화형 인터페이스를 만들어야 합니다. 프론트엔드 개발 분야의 두 가지 중요한 기술인 PHP와 Vue.js는 함께 사용하면 완벽한 도구라고 볼 수 있습니다. 이 기사에서는 독자가 이 두 가지를 더 잘 이해하고 적용할 수 있도록 PHP와 Vue의 조합과 자세한 코드 예제를 살펴보겠습니다.

                프론트엔드 면접관이 자주 묻는 질문 프론트엔드 면접관이 자주 묻는 질문 Mar 19, 2024 pm 02:24 PM

                프론트엔드 개발 인터뷰에서 일반적인 질문은 HTML/CSS 기초, JavaScript 기초, 프레임워크 및 라이브러리, 프로젝트 경험, 알고리즘 및 데이터 구조, 성능 최적화, 크로스 도메인 요청, 프론트엔드 엔지니어링, 디자인 패턴, 새로운 기술 및 트렌드. 면접관 질문은 후보자의 기술적 능력, 프로젝트 경험, 업계 동향에 대한 이해를 평가하기 위해 고안되었습니다. 따라서 지원자는 자신의 능력과 전문성을 입증할 수 있도록 해당 분야에 대한 충분한 준비를 갖추어야 합니다.

                간단한 JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법 간단한 JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법 Jan 05, 2024 pm 06:08 PM

                JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법, 특정 코드 예제가 필요합니다. 서문: 웹 개발에서는 서버와의 데이터 상호 작용이 종종 포함됩니다. 서버와 통신할 때 반환된 HTTP 상태 코드를 가져와서 작업의 성공 여부를 확인하고 다양한 상태 코드에 따라 해당 처리를 수행해야 하는 경우가 많습니다. 이 기사에서는 JavaScript를 사용하여 HTTP 상태 코드를 얻는 방법과 몇 가지 실용적인 코드 예제를 제공합니다. XMLHttpRequest 사용

                Django는 프론트엔드인가요, 백엔드인가요? 확인 해봐! Django는 프론트엔드인가요, 백엔드인가요? 확인 해봐! Jan 19, 2024 am 08:37 AM

                Django는 빠른 개발과 깔끔한 ​​방법을 강조하는 Python으로 작성된 웹 애플리케이션 프레임워크입니다. Django는 웹 프레임워크이지만 Django가 프런트엔드인지 백엔드인지에 대한 질문에 답하려면 프런트엔드와 백엔드의 개념에 대한 깊은 이해가 필요합니다. 프론트엔드는 사용자가 직접 상호작용하는 인터페이스를 의미하고, 백엔드는 HTTP 프로토콜을 통해 데이터와 상호작용하는 서버측 프로그램을 의미합니다. 프론트엔드와 백엔드가 분리되면 프론트엔드와 백엔드 프로그램을 독립적으로 개발하여 각각 비즈니스 로직과 인터랙티브 효과, 데이터 교환을 구현할 수 있습니다.

                선택된 Java JPA 인터뷰 질문: 지속성 프레임워크에 대한 숙달도 테스트 선택된 Java JPA 인터뷰 질문: 지속성 프레임워크에 대한 숙달도 테스트 Feb 19, 2024 pm 09:12 PM

                JPA 란 무엇입니까? JDBC와 어떻게 다른가요? JPA(JavaPersistence API)는 ORM(객체 관계형 매핑)을 위한 표준 인터페이스로, 이를 통해 Java 개발자는 데이터베이스에 대해 직접 SQL 쿼리를 작성하지 않고도 친숙한 Java 객체를 사용하여 데이터베이스를 작동할 수 있습니다. JDBC(JavaDatabaseConnectivity)는 데이터베이스에 연결하기 위한 Java의 표준 API로, 개발자가 데이터베이스를 작동하려면 SQL 문을 사용해야 합니다. JPA는 JDBC를 캡슐화하고 객체 관계형 매핑을 위한 보다 편리하고 높은 수준의 API를 제공하며 데이터 액세스 작업을 단순화합니다. JPA에서 엔터티란 무엇입니까? 실재

                Go 언어 프런트엔드 기술 탐색: 프런트엔드 개발을 위한 새로운 비전 Go 언어 프런트엔드 기술 탐색: 프런트엔드 개발을 위한 새로운 비전 Mar 28, 2024 pm 01:06 PM

                빠르고 효율적인 프로그래밍 언어인 Go 언어는 백엔드 개발 분야에서 널리 사용됩니다. 그러나 Go 언어를 프런트엔드 개발과 연관시키는 사람은 거의 없습니다. 실제로 프런트엔드 개발에 Go 언어를 사용하면 효율성이 향상될 뿐만 아니라 개발자에게 새로운 지평을 열어줄 수도 있습니다. 이 기사에서는 프런트엔드 개발에 Go 언어를 사용할 수 있는 가능성을 살펴보고 독자가 이 영역을 더 잘 이해할 수 있도록 구체적인 코드 예제를 제공합니다. 전통적인 프런트엔드 개발에서는 사용자 인터페이스를 구축하기 위해 JavaScript, HTML, CSS를 사용하는 경우가 많습니다.

                JavaScript에서 HTTP 상태 코드를 쉽게 얻는 방법 JavaScript에서 HTTP 상태 코드를 쉽게 얻는 방법 Jan 05, 2024 pm 01:37 PM

                JavaScript에서 HTTP 상태 코드를 얻는 방법 소개: 프런트 엔드 개발에서 우리는 종종 백엔드 인터페이스와의 상호 작용을 처리해야 하며 HTTP 상태 코드는 매우 중요한 부분입니다. HTTP 상태 코드를 이해하고 얻는 것은 인터페이스에서 반환된 데이터를 더 잘 처리하는 데 도움이 됩니다. 이 기사에서는 JavaScript를 사용하여 HTTP 상태 코드를 얻는 방법을 소개하고 구체적인 코드 예제를 제공합니다. 1. HTTP 상태 코드란 무엇입니까? HTTP 상태 코드는 브라우저가 서버에 요청을 시작할 때 서비스가

                프런트엔드 모듈형 ESM이란 무엇입니까? 프런트엔드 모듈형 ESM이란 무엇입니까? Feb 25, 2024 am 11:48 AM

                프론트엔드 ESM이란 무엇입니까? 프론트엔드 개발에서 ESM은 ECMAScript 사양을 기반으로 한 모듈식 개발 방법인 ECMAScriptModules를 참조합니다. ESM은 더 나은 코드 구성, 모듈 간 격리, 재사용성과 같은 많은 이점을 제공합니다. 이 기사에서는 ESM의 기본 개념과 사용법을 소개하고 몇 가지 구체적인 코드 예제를 제공합니다. ESM의 기본 개념 ESM에서는 코드를 여러 모듈로 나눌 수 있으며 각 모듈은 다른 모듈에 대한 일부 인터페이스를 노출합니다.

                See all articles