ES6新特性 模块

ES6模块 intro

在ES6之前,实现模块化使用的是RequireJSseaJS(分别是基于AMD规范的模块化库,和基于CMD规范的模块化库) 见后“JS的模块化书写规范”。
ES6中引入了模块化,其设计思想是 在编译时就能确定模块的依赖关系及输出和输入的变量
ES6的模块化分为导入和导出(export import)。

  • ES6模块 details
    • 自动开启严格模式。
    • 模块中可以导入|导出各种类型的变量(如对象,函数,字符串,数值,布尔值,类等)。
    • 每个模块有自己的上下文context,每一个模块内声明的变量是局部变量,不会污染到全局作用域。
    • 每个模块只加载一次(单例)。对同一文件之后的加载,直接从内存中读取。

exportimport

  • 基本用法
    模块可以导入导出各种类型的变量,如字符串,数值,函数,类。

    • 导出的函数声明与类声明必须要有名称(export default命令再说)
    • 可以导出声明,也可以导出引用(如函数的引用)
    • export命令可以出现在模块的任何位置,但必须在模块顶层
    • import命令会提升到整个模块的头部,首先执行。
    // a.js
    var myName = "JT";
    var myFunc = function() {
        return `name = ${myName}`;
    }
    var myClass = class MyClass {
        static msg = "hello 测试";
    }
    export {myNAme, myFunc, myClass};
    
    // b.js
    import {myName, myFunc, myClass} from "./a.js";
    alert(myName);
    alert(myFunc());
    alert(myClass.msg);
    
  • as

    • 模块中导出的接口可以在export中用as重命名。
    // a.js
    var myName = "JT";
    export {myName as exportName};
    
    // b.js
    import {exportName} from "./a.js";
    console.log(exportName);
    
    • 多个模块中导出了重名的接口,可以在import中用as重命名。
    // a1.js
    var myName = "a1";
    export {myName};
    
    // a2.js
    var myName = "a2";
    export {myName};
    
    // b.js
    import {myName as name1} from "./a1.js";
    import {myName as name2} from "./a2.js";
    console.log(name1, name2);
    
  • import

    • 只读属性:不能改引用的值,但可以改写引用指向的对象的属性的值。
    import {a} from "./xxx.js";
    // a = {};  // error,不能直接修改引用的指向。
    
    a.foo = "hello";  // 可以改对象的属性值。
    
    • 单例模式:对同一文件,就算有多条import指令,但只执行一次import
    import {a} from "./xxx.js"; // 只执行一次
    import {a} from "./xxx.js";
    
    import {a} from "./xxx.js";
    import {b} from "./xxx.js";
    // 相当于 import {a, b} from "./xxx.js";
    
    • 静态执行:import是静态执行,所以不能使用表达式和变量。
    import {"f" + "oo"} from "methods"; // error
    
    var module = "methods";
    import {foo} from module; // error
    
    if (true) {   // error
      import {foo} from "method1";
    } else {
      import {foo} from "method2";
    }
    
  • export default
    使用export default导出默认的变量,这个变量可以用任意变量来接收。

    • 在一个文件(模块)中,exportimport可以有多个,但是export default只有一个。
    • export default中的default是对应的导出接口变量。
    • 通过export方式导出,在导入时要加{}export default不需要大括号。
    • export default向外暴露的成员,可以使用任意变量来接收。
    var a = "hello test";
    export default a; // 只有一个
    
    import b from "./xxx.js"; // 不需要加{},使用任意变量接收。
    
  • 复合使用
    exportimport可以在同一模块使用

    • 可以将导出接口改名,包括default
    • 可以导出全部
    • 当前模块导出的接口会覆盖继承导出的。
    export {foo, bar} from "methods";
    
    // 
    import {foo, bar} from "methods";
    export {foo, bar};
    
    // 重命名接口
    export {foo as bar} from "methods";
    export {foo as default} from "methods";
    export {default as foo} from "methods";
    
    export * from "methods";
    

JS的模块化书写规范

  • CommonJS 用于服务器端,同步,如NoteJS
  • AMDCMD用于浏览器端,异步
    • AMD规范 如requireJS
    • CMD规范 如seaJS
  1. CommonJS
    CommonJS规范诞生较早。NodeJS就采用了CommonJS
var clock = require("clock");
clock.start();

以上为加载模块的方式,这种写法适合服务端(服务端是在本地磁盘读取模块)。

  • CommonJS details
    • 一个单独的文件就是一个模块
    • require()方法加载模块(该方法读取一个文件并执行,最后返回文件内部的exports对象)。
    • require()方法默认读取JS文件,所以.js后缀可省略。

但如果是在客户端的浏览器中加载远程(服务器中)的模块,(同步加载)可能会“假死”,需要能异步加载模块的方式。
于是有了AMDCMD方案。

  1. AMD(Asynchronous Module Definition) 异步的模块定义
    requireJS应用了AMD规范先定义所有依赖,然后在加载完成后的callback中执行
    语法:require([module], callback);,如:
require(["clock"], function(clock) {
  clock.start();
});
  • AMD的模块支持:对象,函数,构造器,字符串,JSON等各种类型。

AMD虽然实现了异步加载,但是它刚开始就把所有依赖写出来,这不符合书写的逻辑顺序。
所以我们又有了新的需求:
我们需要可以像CommonJS那样在使用时在require,并且支持 异步加载后再执行。所以就出现了CMD,他不仅也异步,而且更通用。

  1. CMD(Common Module Definition) 通用的模块定义
    CMDseajs推崇的规范。其写法如下:
define(function(require, exports, module) {
  var clock = require("clock");
  clock.start();
});
  • AMDCMD
    • same: 异步加载模块
    • diff:
      • 对依赖模块的执行时机处理不同
        • ADM 依赖前置 好处:JS可以方便知道有哪些依赖,立即加载。
        • CMD 就近依赖 缺点:需要把模块变为字符串解析以便才知道所依赖的模块。
          典型的牺牲运行时间(解析模块的用时),加快开发速度
      • 职责单一
        • AMD严格区分推崇职责单一,中的require分全局和局部。
        • CMD中没有全局的require,提供seajs.use()实现模块的加载启动。

你可能感兴趣的:(JS)