ES6 표준 시작 요약(Module 구문)

9858 단어

개술


ES6 모듈의 디자인 사상은 가능한 한 정태화되어 번역할 때 모듈의 의존 관계와 입력과 출력의 변수를 확정할 수 있도록 하는 것이다.
CommonJS 모듈은 개체이며 개체 등록 정보를 입력해야 합니다.이런 로드를 '실행할 때 로드' 라고 부른다. 실행할 때만 이 대상을 얻을 수 있기 때문에 컴파일할 때 '정적 최적화' 를 할 수 없다.
// CommonJS 
let { stat, exists, readFile } = require('fs');

//  
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;

ES6 모듈은 개체가 아닌 export 명령을 통해 출력된 코드를 명시적으로 지정하고 import 명령을 통해 입력합니다.
// ES6 
import { stat, exists, readFile } from 'fs';

위 코드의 실질은 fs 모듈에서 세 가지 방법을 불러오고 다른 방법은 불러오지 않습니다.이런 로드를'컴파일할 때 로드'또는 정적 로드라고 부른다. 즉, ES6는 컴파일할 때 모듈 로드를 완성할 수 있어 CommonJS 모듈의 로드 방식보다 효율이 높다.물론 이는 대상이 아니기 때문에 ES6 모듈 자체를 인용할 수 없게 만든다.
컴파일할 때 불러와서 정적 분석을 가능하게 합니다.이것만 있으면 자바스크립트의 문법을 더욱 넓힐 수 있다. 예를 들어 매크로(macro)와 유형 검사(type system)라는 정적 분석으로만 실현될 수 있는 기능을 도입할 수 있다.

엄격한 패턴

  • 변수는 반드시 성명한 후에 사용해야 한다
  • 함수의 매개 변수는 동명 속성이 있을 수 없습니다. 그렇지 않으면 오류 보고
  • with 문장을 사용할 수 없음
  • 읽기 전용 속성에 값을 부여할 수 없습니다. 그렇지 않으면 오류 보고
  • 접두사 0을 사용하여 8진수를 표시할 수 없으며, 그렇지 않으면 오류 보고
  • 삭제할 수 없는 속성을 삭제할 수 없습니다. 그렇지 않으면 오류 보고
  • 변수 delete prop을 삭제할 수 없습니다. 오류가 발생할 수 있습니다. 속성 delete 글로벌 [prop]
  • 만 삭제할 수 있습니다.
  • eval은 외부 작용역에 변수를 도입하지 않습니다
  • eval과arguments는 재할당할 수 없음
  • arguments는 함수 매개 변수의 변화를 자동으로 반영하지 않는다
  • arguments를 사용할 수 없습니다.callee
  • arguments를 사용할 수 없습니다.caller
  • this는 전역 대상을 가리키는 것을 금지하고 맨 윗부분의this는undefined를 가리키며 맨 윗부분 코드에서this를 사용하지 말아야 한다.
  • fn.caller 및 f.arguments 함수 호출 창고 가져오기
  • 보존자 증가(예를 들어 보호자, static,interface)
  • ES6의 모듈은 자동으로 엄격한 모드를 사용합니다. 모듈 머리에'use strict'를 붙이든지 말든지.

    export 명령


    모듈 내부의 변수를 외부에서 읽을 수 있도록 하려면, 이 변수를 export 키워드로 출력해야 합니다.
    통상적으로 export 출력의 변수는 원래 이름이지만 as 키워드로 이름을 바꿀 수 있습니다.
    function v1() { ... }
    function v2() { ... }
    
    export {
      v1 as streamV1,
      v2 as streamV2,
      v2 as streamLatestVersion
    };
    //  ,v2 。
    
    // function class 
    //  , , 。
    //  
    
    //  
    function f() {}
    export f;
    
    //  
    export function f() {};
    
    //  
    function f() {}
    export {f};
    

    export 문장 출력의 인터페이스는 그에 대응하는 값과 동적 귀속 관계이다. 즉, 이 인터페이스를 통해 모듈 내부의 실시간 값을 얻을 수 있다.
    export var foo = 'bar';
    setTimeout(() => foo = 'baz', 500);
    

    위 코드 출력 변수foo,값은bar,500밀리초 후baz가 됩니다.CommonJS 사양과는 전혀 다릅니다.CommonJS 모듈은 동적 업데이트가 없는 값의 캐시를 출력합니다.
    export 명령은 모듈의 모든 위치에 나타날 수 있으며, 모듈의 맨 위에 있으면 됩니다.블록 레벨 역할 영역에 있으면 오류가 발생합니다. import 명령도 마찬가지입니다.조건 코드 블록에 있으면 정적 최적화를 할 수 없기 때문에 ES6 모듈의 설계 취지에 어긋난다.

    import 명령


    import 명령은 다른 모듈에서 가져올 변수 이름을 지정하는 괄호를 받아들입니다.괄호 안의 변수 이름은 가져온 모듈의 대외 인터페이스 이름과 같아야 합니다.
    입력한 변수의 이름을 다시 찾으려면 import 명령은 as 키워드를 사용하고 입력한 변수의 이름을 바꿉니다.
    import { name as newName } from './test.js';
    

    import 명령에서 입력한 변수는 모두 읽기 전용입니다. 왜냐하면 본질은 입력 인터페이스이기 때문입니다.모듈을 불러오는 스크립트에서 인터페이스를 바꾸는 것을 허용하지 않는다는 것이다.단, 만약에 a가 하나의 대상이라면 a의 속성을 바꾸는 것은 허용된다.(권장하지 않음)
    import 뒤에 있는from은 모듈 파일의 위치를 지정합니다. 상대적인 경로일 수도 있고 절대적인 경로일 수도 있습니다.js 접미사는 생략할 수 있습니다.모듈 이름만 있고 경로가 없는 경우 JavaScript 엔진에 모듈 위치를 알려주는 구성 파일이 있어야 합니다.
    import 명령은 향상 효과가 있어 전체 모듈의 머리로 올라가 먼저 실행됩니다.import 명령은 코드가 실행되기 전에 컴파일 단계에서 실행되기 때문입니다.
    import은 정적 실행이기 때문에 표현식과 변수를 사용할 수 없습니다. 실행할 때만 결과를 얻을 수 있는 문법 구조입니다.
    //  
    import { 'f' + 'oo' } from 'my_module';
    
    //  
    let module = 'my_module';
    import { foo } from module;
    
    //  
    if (x === 1) {
      import { foo } from 'module1';
    } else {
      import { foo } from 'module2';
    }
    

    import 문장은 불러오는 모듈을 실행합니다.같은 import 문장을 여러 번 반복하면 한 번만 실행하고 여러 번 실행하지 않습니다.
    import 'lodash';
    import 'lodash'; 
    //  
    
    import { foo } from 'my_module';
    import { bar } from 'my_module';
    
    //  
    import { foo, bar } from 'my_module';
    
    // import  Singleton  。
    
    //  , , (*) , 。
    import * as circle from './circle';
    

    현재 단계에서는 Babel 디코딩, CommonJS 모듈의 Require 명령과 ES6 모듈의 import 명령을 통해 같은 모듈에 쓸 수 있지만 이렇게 하지 않는 것이 좋다.import은 정적 해석 단계에서 실행되기 때문에 모듈 중 가장 먼저 실행됩니다.

    export default 명령


    import 명령을 사용할 때, 사용자는 불러올 변수 이름이나 함수 이름을 알아야 합니다. 그렇지 않으면 불러올 수 없습니다.(* 기호를 사용하여 전체적으로 로드하지 않는 한)
    모듈의 기본 출력을 지정하는 export default 명령입니다.다른 모듈이 이 모듈을 불러올 때 import 명령은 불러오는 모듈에 임의의 이름을 지정할 수 있습니다.
    // export-default.js
    export default function () {
      console.log('foo');
    }
    
    // import-default.js
    import customName from './export-default';
    customName(); // 'foo
    

    export default 명령은 모듈의 기본 출력을 지정하는 데 사용됩니다.분명히 하나의 모듈은 기본 출력만 있을 수 있기 때문에 export default 명령은 한 번만 사용할 수 있습니다.따라서 import 명령 뒤에는 괄호를 늘릴 필요가 없습니다. 왜냐하면 유일하게 export default 명령에 대응할 수 있기 때문입니다.만약 export 출력을 사용한다면, import을 사용할 때는 반드시 괄호를 사용해야 한다.
    본질적으로, export default는default라는 변수나 방법을 출력한 다음에 시스템에서 임의의 이름을 지을 수 있도록 합니다. 바로default 변수를 출력했기 때문에 그 뒤에 변수와 문장을 설명할 수 없습니다.
    //  
    var a = 1;
    export default a;
    
    //  
    export default var a = 1;
    
    //  , default
    export default 42;
    
    //  ,  
    export 42;
    
    //  
    export default class { ... } //  
    

    import 문장에 기본 방법과 다른 인터페이스를 동시에 입력하려면 다음과 같이 쓰십시오.
    import _, { each, forEach } from 'lodash';
    
    //  
    export default function (obj) {
      // ···
    }
    
    export function each(obj, iterator, context) {
      // ···
    }
    
    export { each as forEach };
    

    export와 import의 복합 쓰기


    만약 한 모듈에서 먼저 입력한 후에 같은 모듈을 출력한다면 import 문장은 export 문장과 함께 쓸 수 있습니다.
    export { foo, bar } from 'my_module';
    
    //    my_module.js foo bar, 
    import { foo, bar } from 'my_module';
    export { foo, bar };
    
    //  
    export { es6 as default } from './someModule';
    
    //  
    import { es6 } from './someModule';
    export default es6;
    

    그러나 주의해야 할 것은 한 줄로 쓴 후에foo와bar는 실제적으로 현재 모듈에 도입되지 않았고 이 두 인터페이스를 대외적으로 전송한 것과 같아서 현재 모듈은foo와bar를 직접 사용할 수 없다.

    모듈의 계승


    circleplus 모듈이 있다고 가정하면 circle 모듈을 계승합니다.
    //   circleplus.js
    
    export * from 'circle';
    //  circle , 
    // export * circle default 
    //  default  
    //   circle
    export var e = 2.71828182846;
    export default function(x) {
      return Math.exp(x);
    }
    
    //  
    
    import * as math from 'circleplus';
    import exp from 'circleplus';
    console.log(exp(math.e));
    

    circle의 속성이나 방법을 바꾸어 출력할 수도 있습니다.
    export { area as myArea } from 'circle';
    //  circle area , myArea。
    

    전체 모듈 상수


    이 책은 const 명령을 소개할 때 const 성명의 상수는 현재 코드 블록에만 유효하다고 말했다.크로스 모듈의 상수(즉 여러 파일)를 설정하거나 한 값이 여러 모듈에 공유되려면 아래의 쓰기를 사용하십시오.
    // constants.js  
    export const A = 1;
    export const B = 3;
    export const C = 4;
    
    // test1.js  
    import * as constants from './constants';
    console.log(constants.A); // 1
    console.log(constants.B); // 3
    
    // test2.js  
    import {A, B} from './constants';
    console.log(A); // 1
    console.log(B); // 3
    

    사용할 상수가 매우 많으면, 전문적인 constants 디렉터리를 만들어서, 각종 상수를 다른 파일에 써서 이 디렉터리에 저장할 수 있습니다.
    //  
    // constants/db.js
    export const db = {
      url: 'xxx',
      admin_username: 'admin',
      admin_password: 'admin password'
    };
    
    // constants/user.js
    export const users = ['root', 'admin', 'staff', 'ceo', 'chief', 'moderator'];
    
    // constants/index.js  , 。
    export {db} from './db';
    export {users} from './users';
    
    // =============================
    
    //  
    // script.js
    import {db, users} from './constants/index';
    

    import()


    import와 export 명령은 모듈의 맨 위에서만 사용할 수 있으며 코드 블록에서는 사용할 수 없습니다. 위에서 말했듯이 이것은 정적 분석을 해야 하기 때문에 컴파일할 때 import 문장을 처리해야 합니다.
    이러한 디자인은 컴파일러의 효율을 높이는 데 유리하지만 실행할 때 모듈을 불러올 수 없게 한다.문법적으로 조건이 불러오면 실현될 수 없다.만약 import 명령이 노드의 Require 방법을 대체하려고 한다면, 이것은 장애가 된다.리퀘스트는 실행할 때 불러오는 모듈이기 때문에, import 명령은 리퀘스트의 동적 불러오는 기능을 대체할 수 없습니다.
    따라서 import () 함수를 도입하여 동적 불러오는 것을 제안합니다.
    import(specifier)
    

    위 코드에서 import 함수의 매개 변수specifier는 불러올 모듈의 위치를 지정합니다.import 명령은 어떤 파라미터를 받아들일 수 있고 import () 함수는 어떤 파라미터를 받아들일 수 있으며, 이들의 차이는 주로 후자가 동적 불러오는 것이다.
    import()가 Promise 객체를 반환합니다.
    const main = document.querySelector('main');
    
    import(`./section-modules/${someVariable}.js`)
      .then(module => {
        module.loadPageInto(main);
      })
      .catch(err => {
        main.textContent = err.message;
      });
    

    import () 함수는 모듈뿐만 아니라 모듈이 아닌 스크립트에서도 사용할 수 있습니다.실행 중입니다.
    import () 는 노드의 Require 방법과 유사한데, 차이점은 전자는 비동기적인 로드이고, 후자는 동기적인 로드이다.

    적용 장면1: 필요에 따라 로드

    //  , 。
    button.addEventListener('click', event => {
      import('./dialogBox.js')
      .then(dialogBox => {
        dialogBox.open();
      })
      .catch(error => {
        /* Error handling */
      })
    });
    

    적용 장면2: 조건 로드

    //  , 。
    if (condition) {
      import('moduleA').then(...);
    } else {
      import('moduleB').then(...);
    }
    

    적용 장면3: 동적 모듈 경로

    //  f   f , 
    import(f())
    .then(...);
    

    주의점


    import () 마운트 모듈이 성공하면 이 모듈은then 방법의 매개 변수로 대상이 됩니다.따라서 대상이 값을 해체하는 문법을 사용하여 출력 인터페이스를 얻을 수 있다.
    모듈에default 출력 인터페이스가 있으면 매개 변수로 직접 얻을 수 있습니다.
    import('./myModule.js')
    .then(myModule => {
      console.log(myModule.default);
    });
    
    //  
    
    import('./myModule.js')
    .then(({default: theDefault}) => {
      console.log(theDefault);
    });
    

    여러 모듈을 동시에 불러오려면 아래의 쓰기 방법을 사용하십시오.
    Promise.all([
      import('./module1.js'),
      import('./module2.js'),
      import('./module3.js'),
    ])
    .then(([module1, module2, module3]) => {
       ···
    });
    

    import () 는 async 함수에도 사용할 수 있습니다. 프로미스 대상을 되돌려주기 때문에 await 뒤를 따라 동적 동기화 불러올 수 있습니다.

    좋은 웹페이지 즐겨찾기