>  기사  >  웹 프론트엔드  >  ES6 모듈에 대한 자세한 설명

ES6 모듈에 대한 자세한 설명

青灯夜游
青灯夜游앞으로
2019-11-29 17:45:452043검색

ES6 모듈에 대한 자세한 설명

현재 거의 모든 프로젝트는 웹팩, 롤업 및 기타 빌드 도구를 기반으로 개발되었으며 모듈화가 표준이 되었습니다.

오늘은 ES6의 모듈 메커니즘을 체계적으로 검토하고 일반적인 작업과 모범 사례를 요약하겠습니다.

몇 가지 간단한 배경

사용 준비가 완료되었으며 우리 모두가 달성하고자 하는 메커니즘입니다.

Javascript에서도 마찬가지입니다. 큰 Javascript 프로그램을 여러 부분으로 나누어서 사용할 부분만 가져가세요.

[관련 과정 권장 사항: JavaScript 비디오 튜토리얼]

오랫동안 NodeJS에는 이러한 기능이 있었으며 나중에 점점 더 많은 라이브러리와 프레임워크에도 CommonJS 또는 AMD 모델 기반 구현과 같은 모듈 기능이 있습니다. RequireJs와 같은) 및 후속 Webpack, Babel 등

2015년에는 표준 모듈형 시스템이 탄생했습니다. 이것이 오늘 이야기할 주인공인 ES6 모델 시스템입니다.

언뜻 보면 ES6 모델 시스템이 CommonJS 구문과 매우 유사하다는 것을 쉽게 알 수 있습니다. 결국 ES6 모델 시스템은 CommonJS 시대에서 왔으며 CommonJS의 영향을 많이 받았습니다.

CommonJs와 같은 간단한 예를 살펴보세요: (https://flaviocopes.com/commonjs/)

//file.js
module.exports = value;

// 引入value
const value = require('file.js')

그리고 ES6에서는:

// const.js
export const value = 'xxx';


import { value } from 'const.js'

구문은 매우 유사합니다.

이제 ES6 모듈에 대해 자세히 알아보기 위해 주로 가져오기 및 내보내기 및 여러 관련 기능을 살펴보겠습니다.

모듈화의 이점

모듈화의 주요 이점은 두 가지입니다.

1. 避免全局变量污染
2. 有效的处理依赖关系

시대가 발전하면서 브라우저도 es6 가져오기 및 내보내기 구문을 기본적으로 지원하기 시작했습니다.

ES6 모듈에 대한 자세한 설명

먼저 간단한 예를 살펴보겠습니다.

<script>
  import { addTextToBody } from &#39;/util.js&#39;;

  addTextToBody(&#39;Modules are pretty cool.&#39;);
</script>

// util.js 
export function addTextToBody(text) {
  const p = document.createElement('p');
  p.textContent = text;
  document.body.appendChild(p);
}

이벤트를 처리하려는 경우에도 마찬가지입니다. 간단한 예를 살펴보겠습니다.

<button>Show Message</button>
<script></script>

// showImport.js
import { showMessage } from '/show.js'

document.getElementById('test').onclick = function() {
  showMessage();
}

// show.js
export function showMessage() {
  alert("Hello World!")
}

이 데모를 실행하려면 다음을 설정해야 합니다. 간단한 서비스 시작:

$ http-server

그렇지 않으면 CORS 오류가 발생합니다.

오류의 구체적인 이유와 기타 세부 사항은 이 글의 초점이 아닙니다. 관심이 있으시면 다음 링크를 자세히 읽어보실 수 있습니다.

https://jakearchibald.com/2017/es-modules-in-browsers/

엄격 모드

https://developer.mozilla.org/en-US/docs/Web/JavaScript/ Reference/Strict_mode

'use strict' 문은 우리에게 익숙합니다. es5 시대에 자주 사용하는 문입니다. 일반적으로 이 문은 Javascript의 친숙하지 않은 부분을 비활성화하고 도움을 주기 위한 것입니다. 더 엄격하게 코드를 작성하세요.

이 기능은 es6 구문에서 기본적으로 활성화됩니다. 코드에 덜 엄격한 코드가 있으면 오류가 보고됩니다. 예:

ES6 모듈에 대한 자세한 설명

다음은 MDN에서 추출한 몇 가지 엄격한 코드입니다. <code>비활성화된 패턴 부분: 严格模式中被禁用的部分:

  • Variables can’t be left undeclared
  • Function parameters must have unique names (or are considered syntax errors)
  • with is forbidden
  • Errors are thrown on assignment to read-only properties
  • Octal numbers like 00840 are syntax errors
  • Attempts to delete undeletable properties throw an error
  • delete prop is a syntax error, instead of assuming delete global[prop]
  • eval doesn’t introduce new variables into its surrounding scope
  • eval and arguments can’t be bound or assigned to
  • arguments doesn’t magically track changes to method parameters
  • arguments.callee throws a TypeError, no longer supported
  • arguments.caller throws a TypeError, no longer supported
  • Context passed as this in method invocations is not “boxed” (forced) into becoming an Object
  • No longer able to use fn.caller and fn.arguments to access the JavaScript stack
  • Reserved words
    • 변수는 선언되지 않은 채로 둘 수 없습니다
    • 함수 매개변수에는 <code>고유한 이름이 있어야 합니다(또는 구문 오류로 간주됩니다)
  • with는 금지됩니다

  • read-에 할당하면 오류가 발생합니다. 00840과 같은 속성
  • 8진수구문 오류입니다.
  • 삭제할 수 없는 속성을 삭제하려고 하면 오류가 발생합니다.
  • delete prop은 구문 오류입니다. delete global[prop]
  • eval이 주변 범위에 새 변수를 도입하지 않는다고 가정하는 대신eval 및 인수는

  • 인수에 바인딩되거나 할당될 수 없습니다. 메소드 매개변수
  • 인수에 대한 변경 사항을 마술처럼 추적하지 않습니다. 피호출자 는 더 이상 지원되지 않는 TypeError를 발생시킵니다.

  • arguments.caller는 더 이상 지원되지 않는 TypeError를 발생시킵니다.
  • 메서드 호출에서 전달된 컨텍스트는 "박스 처리"되지 않습니다( 강제)가 Object

  • 더 이상 fn.caller 및 fn.arguments를 사용하여 JavaScript 스택
  • 예약어에 액세스할 수 없습니다(예: protected). , static, 인터페이스 등)은 바인딩할 수 없습니다

    여러 가지 내보내기 용도

    ES6 모듈은 정적 내보내기만 지원하며 모듈의 가장 바깥쪽 범위에서만 내보내기를 사용할 수 있으며 조건문에서는 사용할 수 없습니다. . , 함수 범위에서도 사용할 수 없습니다.

    🎜분류 측면에서 내보내기에는 세 가지 주요 유형이 있습니다. 🎜🎜1. 명명된 내보내기(모듈당 0개 이상의 내보내기) 🎜🎜2. 기본 내보내기(모듈당 1개) 🎜🎜3. 개요: 🎜 🎜
    // Exporting inpidual features
    export let name1, name2, …, nameN; // also var, const
    export let name1 = …, name2 = …, …, nameN; // also var, const
    export function functionName(){...}
    export class ClassName {...}
    
    // Export list
    export { name1, name2, …, nameN };
    
    // Renaming exports
    export { variable1 as name1, variable2 as name2, …, nameN };
    
    // Exporting destructured assignments with renaming
    export const { name1, name2: bar } = o;
    
    // Default exports
    export default expression;
    export default function (…) { … } // also class, function*
    export default function name1(…) { … } // also class, function*
    export { name1 as default, … };
    
    // Aggregating modules
    export * from …; // does not set the default export
    export * as name1 from …;
    export { name1, name2, …, nameN } from …;
    export { import1 as name1, import2 as name2, …, nameN } from …;
    export { default } from …;
    🎜 이제 내보내기의 일반적인 사용법을 소개하겠습니다. 🎜

    1. Named exports (导出每个函数/变量)

    具名导出,这种方式导出多个函数,一般使用场景比如 utils、tools、common 之类的工具类函数集,或者全站统一变量等。

    只需要在变量或函数前面加 export 关键字即可。

    //------ lib.js ------
    export const sqrt = Math.sqrt;
    
    export function square(x) {
        return x * x;
    }
    export function diag(x, y) {
        return sqrt(square(x) + square(y));
    }
    
    //------ main.js 使用方式1 ------
    import { square, diag } from 'lib';
    console.log(square(11)); // 121
    console.log(diag(4, 3)); // 5
    
    //------ main.js 使用方式2 ------
    import * as lib from 'lib';
    console.log(lib.square(11)); // 121
    console.log(lib.diag(4, 3)); // 5

    我们也可以直接导出一个列表,例如上面的lib.js可以改写成:

    //------ lib.js ------
    const sqrt = Math.sqrt;
    function square(x) {
        return x * x;
    }
    function add (x, y) {
        return x + y;
    }
    export { sqrt, square, add }

    2. Default exports (导出一个默认 函数/类)

    这种方式比较简单,一般用于一个类文件,或者功能比较单一的函数文件使用。

    一个模块中只能有一个export default默认输出。

    export default与export的主要区别有两个:

    不需要知道导出的具体变量名, 导入(import)时不需要{}.

    //------ myFunc.js ------
    export default function () {};
    
    //------ main.js ------
    import myFunc from 'myFunc';
    myFunc();

    导出一个类

    //------ MyClass.js ------
    class MyClass{}
    
    export default MyClass;
    
    //------ Main.js ------
    import MyClass from 'MyClass';

    注意这里默认导出不需要用{}。

    3. Mixed exports (混合导出)

    混合导出,也就是 上面第一点和第二点结合在一起的情况。比较常见的比如 Lodash,都是这种组合方式。

    //------ lib.js ------
    export var myVar = ...;
    export let myVar = ...;
    export const MY_CONST = ...;
    
    export function myFunc() {
      // ...
    }
    export function* myGeneratorFunc() {
      // ...
    }
    export default class MyClass {
      // ...
    }
    
    // ------ main.js ------
    import MyClass, { myFunc } from 'lib';

    再比如lodash例子:

    //------ lodash.js ------
    export default function (obj) {
      // ...
    };
    export function each(obj, iterator, context) {
      // ...
    }
    export { each as forEach };
    
    //------ main.js ------
    import _, { forEach } from 'lodash';

    4. Re-exporting (别名导出)

    一般情况下,export输出的变量就是在原文件中定义的名字,但也可以用 as 关键字来指定别名,这样做一般是为了简化或者语义化export的函数名。

    //------ lib.js ------
    export function getUserName(){
      // ...
    };
    export function setName(){
      // ...
    };
    
    //输出别名,在import的时候可以同时使用原始函数名和别名
    export {
      getName as get, //允许使用不同名字输出两次
      getName as getNameV2,
      setName as set
    }

    5. Module Redirects (中转模块导出)

    有时候为了避免上层模块导入太多的模块,我们可能使用底层模块作为中转,直接导出另一个模块的内容如下:

    //------ myFunc.js ------
    export default function() {...};
     
    //------ lib.js ------
    export * from 'myFunc';
    export function each() {...};
     
    //------ main.js ------
    import myFunc, { each } from 'lib';
    
    export 只支持在最外层静态导出、只支持导出变量、函数、类,如下的几种用法都是错误的。
    
    `错误`的export用法:
    
    //直接输出变量的值
    export 'Mark';
    
    // 未使用中括号 或 未加default
    // 当只有一个导出数,需加default,或者使用中括号
    var name = 'Mark';
    export name;
    
    //export不要输出块作用域内的变量
    function () {
      var name = 'Mark';
      export  { name };
    }

    import的几种用法

    import的用法和export是一一对应的,但是import支持静态导入和动态导入两种方式,动态import支持晚一些,兼容性要差一些。

    ES6 모듈에 대한 자세한 설명

    下面我就总结下import的基本用法:

    1. Import All things

    当export有多个函数或变量时,如文中export的第一点,可以使用 * as 关键字来导出所有函数及变量,同时 as 后面跟着的名称做为 该模块的命名空间。

    //导出lib的所有函数及变量
    import * as lib from 'lib';
    
    //以 lib 做为命名空间进行调用,类似于object的方式
    console.log(lib.square(11)); // 121

    2. Import a single/multiple export from a module

    从模块文件中导入单个或多个函数,与 * as namepage 方式不同,这个是按需导入。如下例子:

    //导入square和 diag 两个函数
    import { square, diag } from 'lib';
    
    // 只导入square 一个函数
    import { square } from 'lib';
    
    // 导入默认模块
    import _ from 'lodash';
    
    // 导入默认模块和单个函数,这样做主要是简化单个函数的调用
    import _, { each } from 'lodash';

    3. Rename multiple exports during import

    和 export 一样,也可以用 as 关键字来设置别名,当import的两个类的名字一样时,可以使用 as 来重设导入模块的名字,也可以用as 来简化名称。
    比如:

    // 用 as 来 简化函数名称
    import {
      reallyReallyLongModuleExportName as shortName,
      anotherLongModuleName as short
    } from '/modules/my-module.js';
    
    // 避免重名
    import { lib as UserLib} from "alib";
    import { lib as GlobalLib } from "blib";

    4. Import a module for its side effects only

    有时候我们只想import一个模块进来,比如样式,或者一个类库。

    // 导入样式
    import './index.less';
    
    // 导入类库
    import 'lodash';

    5. Dynamic Imports

    静态import在首次加载时候会把全部模块资源都下载下来.

    我们实际开发时候,有时候需要动态import(dynamic import)。

    例如点击某个选项卡,才去加载某些新的模块:

    // 当动态import时,返回的是一个promise
    import('lodash')
      .then((lodash) => {
        // Do something with lodash.
      });
    
    // 上面这句实际等同于
    const lodash = await import('lodash');

    es7的新用法:

    async function run() {
        const myModule = await import('./myModule.js');
    
        const { export1, export2 } = await import('./myModule.js');
    
        const [module1, module2, module3] =
            await Promise.all([
                import('./module1.js'),
                import('./module2.js'),
                import('./module3.js'),
            ]);
    }
    
    run();

    总结

    以上, 我总结了ES6 Module 的简单背景和 常见的import , export 用法, 但这远远不是它的全部, 篇幅有限,如果想了解更多, 可以看下面的延伸阅读部分(质量都还不错, 可以看看)。

    本文来自 js教程 栏目,欢迎学习!

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

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