美文网首页
第三十一节: ES6 ESModule

第三十一节: ES6 ESModule

作者: 心存美好 | 来源:发表于2022-02-03 18:35 被阅读0次

    1. Module 模块化

    JavaScript 采用'共享一切'的方式加载代码, 也就是在ES6 之前, JavaScript中定义的一切都共享同一个全局作用域, 这样随着程序复杂度提升的同时,也会带来命名冲突等诸多问题. 因此ES6的一个目标就是解决作用域问题. 也为了使JavaScript 应用程序显得有序, 于是引进了模块

    1.1 模块功能

    模块功能主要由两个命令构成:export和import。

    export命令用于规定模块的对外接口。

    import命令用于输入其他模块提供的功能。

    一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。

    2. 模块的使用

    注意如果需要测试模块化需要放到服务器环境

      <!-- module模块化  import导入    -->
      <script src="02.js"></script> <!--  这里只是引入了脚本 -->
      <!-- 在浏览器上运行的基本上是前端模块化
    在服务器上运行的基本是后端模块化
    后台是给内部员工使用,用来添加数据的。前台给用户看的。都是前端
     -->
    
      <script type="module">
        // module表示模块化。注意:模块化只能在服务器环境运行。服务器环境有端口号,IP地址,协议
        //js的type类型通常是javascript,所以省略,里面就直接写脚本
    
        import './01.js'  //  这样导入js,只是执行了一遍该js文件,拿不到任何数据,不能使用该js中的变量和函数
        // console.log(a);   //此时a是在01.js中定义声明的,这里没法使用。
        //导出模块:想要使用a,要在定义a的文件里写上export let a =10; 导出的是模块对象,再回到需要的地方拿到这个导出的模块对象
        // import * as aa from './01.js';    //导入理解:从路径'./01.js'中导出模块* ,aa作为这个模块的别名
        // console.log(aa);
        // console.log('模块对象里的变量a为',aa.a);
        import { a } from './01.js'//导出的简单写法,很像解构
        console.log(a);   //很像解构因为前面从后面是对象中拿到a
    
    //对应01.js文件中的代码
    export let a =10;
    export let b=20;
    
    2.1. export 导出语法

    使用export 关键字将模块中的一部分代码暴露给其他模块, 可以将export 关键字放在任何变量, 函数,类声明之前, 将其导出

    导出模块

    export 东西

    2.1.1 export 导出(暴露)

    // 单个导出数据(变量)   
    export let a = 10;        //导出变量
    export let b = 20;
    export function add(){    //导出函数
        return a+b
        }
    let c = 'c30'
    console.log('这里是01.js')
    
    //整体导出,一次性导出多个数据
    let a = 10;
    let b = 20;
    let c = 'c30'      
    function add(){    
    return a+b
    }
    add()
    export {    //不能按照对象的写法,只能数据的罗列,类似es6的简写方式
        a,
        b,
        add
    }
    
    

    2.1.2 export`命令输出函数或类(class)

    // 导出函数
    export function multiply(x, y) {
      return x * y;
    };
    
    // 导出类
    export class Penson{
        constructor(name,age){
            this.name = name;
            this.age = age;
        }
    }
    
    

    2.1.3 as关键字重命名

    通常情况下export 输出的变量, 函数或者类就是本来的名字,但是有时,我们可能并不希望使用它们的原始名称. 此时就可以通过as关键字修改导出元素的名称.

    function v1() { ... }
    function v2() { ... }
    
    export {
      v1 as streamV1,
      v2 as streamV2,
    };
    
    

    2.1.4 特别注意

    需要特别注意的是,export命令规定的是对外的接口

    // 报错
    export 1;
    
    // 报错
    var m = 1;
    export m;
    
    //正确写法
    // 写法一
    export var m = 1;
    
    // 写法二
    var m = 1;
    export {m};
    
    // 写法三
    var n = 1;
    export {n as m};
    
    

    同样的,function的输出,也必须遵守这样的写法

    // 报错
    function f() {}
    export f;
    
    // 正确
    export function f() {};
    
    // 正确
    function f() {}
    export {f};
    
    
    动态绑定

    export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。

      <!-- 动态数据导出,异步异出 -->
      <!-- 导入文件 -->
      <script type='module'>
        import { a, b } from './01.js';
        console.log(a, b);   //a,b不是新值
      </script>
      
      <!-- 导出文件 -->
      let a = 10;
     let b = 20;
     function add() {
        return a + b
     }
     setTimeout(() => {   //3秒后导出
        a = 100;
        b = 200;
     }, 3000)
     export { a, b, add }
    
    
     <!-- 动态数据导出,异步异出 -->
       <!-- 导入文件 -->
      <script type='module'>
        import { a, b } from './01.js';
        console.log(a, b);   //a,b不是新值
    
        setTimeout(()=>{
          console.log(a, b);    //这里的值就是更新的了
        },4000)
      </script>
      
        <!-- 导出文件 -->
      let a = 10;
     let b = 20;
     function add() {
        return a + b
     }
     setTimeout(() => {   //3秒后导出
        a = 100;
        b = 200;
     }, 3000)
     export { a, b, add }
    
    2.1.5 整体导出

    发现导入都是需要花括号的,如果希望导入不用花括号,那就需要改变导出方式

    // 导出时使用export default
    let a;
    export default a = 10;
    
    // 导入时可以不用花括号
    <script type="module">
    import a from './modules/1.js'
    
    // 默认导出 export default  注意一个模块只能有一个默认导出
    // export default [ 'a', 'b', 'add' ]  //也可以导出对象,函数等  只能有一个默认导出
    //export default function aa(){
    //    console.log(111);
    //} 
    
    导入文件
      <script type='module'>
        import aa from './01.js';
        console.log(aa);
      </script>
    
    // 同时有默认导出 export default  和变量导出
    export let a=10;
    export let b =20;
    export default function aa(){
        console.log(111);
    }
    
    导入文件
      <script type='module'>
        // 导入方法一
        import * as aa from './01.js';
        console.log(aa);
        console.log(aa.a);
        console.log(aa.b);
        console.log(aa.default);
        // 导入方法二
        import def, { a, b } from './01.js';   //大括号里面的是有名字的,外面的是默认导出的
        console.log(a);
        console.log(b);
        console.log(def);
      </script>
    
    2.2. 导入模块

    使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块。

    引入模块
    import 模块路径

        //正常导入
        import * as js01 from './01.js'   
        console.log(js01);   //打印导入的模块对象
        console.log(js01.a); //这样导入的数据需要打点才能使用,通常不这么用
        
    
       //类似解构的简单的导入方式
        import {a,b,add}from './01.js'  
        console.log(a);  //不用打点,直接使用
        console.log(a,b); 
        console.log(add());
    
    <script type="module">
        import "./modules/1.js";   // 这种写法只是相当于引入一个文件,也叫无绑定导入
        import {a} from "./modules/1.js"   // 导入模块中导出的a 
    </script>
    
    import {firstName, lastName, year} from './profile';
    function setName(element) {
      element.textContent = firstName + ' ' + lastName;
    }
    

    上面代码的import命令,用于加载profile.js文件,并从中输入变量。import命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(profile.js)对外接口的名称相同。

        import {a,b,add}from './01.js'   
        a =100   //导入的数据相当于常量const a =10 ,不能随意再赋值,会报错
    

    2.2.1 as关键字改变量名

    //导出文件里的内容
    let a = 10;
    let b = 20;
    function add(){
        return a+b
        }
    let c = 'c30'
    export {
        a as aaa,     //将变量a通过as改名为aaa,导入时全部使用aaa
        b,
        add as bdd
    }
    
    //导入文件里的内容
        import {aaa,b,bdd}from './01.js'   
        console.log(aaa);     //使用as后的变量名
        console.log(b);
        console.log(bdd());
    

    import后面的from指定模块文件的位置,可以是相对路径,也可以是绝对路径,.js后缀可以省略。

    2.2.2 import 提升
    注意,import命令具有提升效果,会提升到整个模块的头部,首先执行。

    // 导入前引用
    export let a =10;
    
     导入文件
       <script type='module'>
        console.log('我在导入之前的', a * a);   //导入前引用
        import { a } from './01.js';  //程序会将import提升,但最好自己写在最前面
      </script>
    
    foo();
    
    import { foo } from 'my_module';
    //import的执行早于foo的调用。这种行为的本质是,import命令是编译阶段执行的,在代码运行之前。
    

    2.2.3 import不能使用表达式
    由于import是静态执行,所以不能使用表达式和变量,这些只有在运行时才能得到结果的语法结构。

    // 报错   不能拆成表达式
    import { 'f' + 'oo' } from 'my_module';
    
    // 报错  导入不能使用表达式
    let module = 'my_module';  
    import { foo } from module;
    
    // 报错   import只能使用在顶层
    if (x === 1) {
      import { foo } from 'module1';
    } else {
      import { foo } from 'module2';
    }
    
    
    import { foo } from 'my_module';
    import { bar } from 'my_module';
    
    // 等同于
    import { foo, bar } from 'my_module';
    

    2.2.4 模块化整体加载

    除了指定加载某个输出值,还可以使用整体加载,即用星号(*)指定一个对象,所有输出值都加载在这个对象上面。

    注意,模块整体加载所在的那个对象,不允许运行时改变。下面的写法都是不允许的。

    2.2.5 import 特点总结

    1. 可以是相对路径也可以是绝对路径
      import "./modules/1.js";
    2. import模块只会导入一次,无论你引入多少次。模块的导入导出有缓存机制,只有第一次导入会执行一遍并且将数据放入缓存,后面的所有的导入直接到缓存中取数据使用,但不会再执行了。
    3. import "./modules/1.js"; 如果这么用,就相当于引入了一个js文件
    4. 导入模块中的一个变量或常量
    import {a,b,c} from "./modules/1.js"
    

    5.导入时可以取别名使用

    // 导入时也可以修改别名
    export let a =0;
    
    导入的文件
      <script type='module'>
        let a = 1234;//导入的变量与模块中的变量a重名了
        console.log('a还是原来的a',a);   //a已经存在,所以要改别名
        import {a as aa} from './01.js'; 
        console.log('aa是导入时修改的别名',aa); 
      </script>
    
    import {a as aa,b as bb,c as cc} from "./modules/1.js"
    

    6.导入这个模块导出的对象

    import * as obj from './modules/1.js';
    // 这个时候你就以使用obj这个Module对象了
    console.log(obj.a);
    
    

    7.import 的导入语句会进行提升,提升到最顶部,首先执行

    console.log(a + b);   // 能正常获取到a,b的值
    import {a,b} from './1.js'
    

    8.出去的模块内容,如果里面有定时器发生导出内容的改变,改变的内容会根据定时器自动同步缓存中的内容,所以外边导入的内容也会实时发生改变,不像Comment会缓存。

    2.2.6 import() 动态引入

    默认的import语法不能写在if之类的判断里的,因为是静态引入,先引入在使用

    // 这种写法是错的
    let a = 12;
    if(a == 12){
        import {a} from './1.js'
    }else{
        import {a} from './2.js'
    }
    
    

    import()是动态引入 类似于node里面的require

      //动态导入模块(按需导入)import()返回promise
      let flag=false;
      if(flag){
        import('./01.js')
        .then(data=>{
          console.log('data',data);
        })
      }else{
        import('./02.js')
        .then(res=>{
          console.log('res',res);
        })
      }
    
    
      //动态导入模块返回promise优化写法
        let flag = true;
        let url = flag ? './01.js' : './02.js'
        import(url)
          .then(res => {
            console.log('res', res);
          })
    

    优点:

    1. 按需加载
    2. 可以写在if里面,判断加载
    3. 路径都可以是动态的

    例子:

    / 这里是1.js
    let a = 20;
    let b = 30;
    export {
      a, b
    }
    
    
    // 这里是2.js
    import { a, b } from './1.js';
    console.log(`a的值是:${a}, b的值是:${b}`);
    
    const sum = () => {
      console.log(`我是a,b的和:${a + b}`);
      return a + b;
    }
    const show = () => {
      console.log('show 执行了')
      return 1;
    }
    
    function Person(name, age) {
      this.name = name;
      this.age = age;
      this.showName = function () {
        return `我的名字是${this.name}`;
      }
    }
    
    export {
      sum,
      show,
      a,
      b
    }
    export default { Person }
    
    // 这里是HTML导入
    import mod, { sum, show, a, b } from "./2.js"
    console.log(mod);
    
    let p = new mod.Person("wuwei", 18);
    console.log(p);
    console.log(p.showName());
    
    show();
    
    sum();
    
    console.log(a, b);
    
    // 所有导出只能在顶层导出
    if(true){    
        export let a=10;    //这不是顶层所以报错,不能通过条件判断和函数再导出,嵌套导出会报错
    }else{
        export let a=200;
    }
    
    导入文件
      <script type='module'>
        import {a} from './01.js';   //大括号里面的是有名字的,外面的是默认导出的
        console.log(a); 
      </script>
    
    // 导出只能在顶层导出,可以这样写
    let a =0;
    if(true){    
        a=10;    
    }else{
        a=200;
    }
    export{a}    //整体导出才可以
    
    导入文件
      <script type='module'>
        import {a} from './01.js';   //大括号里面的是有名字的,外面的是默认导出的
        console.log(a); 
      </script>
    

    相关文章

      网友评论

          本文标题:第三十一节: ES6 ESModule

          本文链接:https://www.haomeiwen.com/subject/ustjkrtx.html