美文网首页
Module 模块加载

Module 模块加载

作者: liwuwuzhi | 来源:发表于2019-02-13 16:11 被阅读0次

    ES6 模块规范

    ES6 的模块功能主要由两个命令构成: exportimport
    export 命令用于规定模块的对外接口。
    import 命令用于输入其他模块提供的功能。

    ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";。

    export 命令

    export 的写法如下:

    // 写法一
    export var foo = 1;
    
    // 写法二
    var foo = 1;
    export {foo };
    
    // 写法三
    var foo = 1;
    export {n as foo };
    

    foo 可以是变量,常量,函数function 或 类class


    import 命令

    // 写法一
    import { foo } from 'util'
    import { bar} from 'util'
    
    
    // 写法二
    import { foo, bar } from 'util'
    
    
    // 写法三
    import { foo as surname } from 'util';
    
    // 写法四
    import * as u from 'util';
    console.log(u.foo, u.bar)
    

    01
    import 后面的 from 指定模块文件的位置,可以是相对或绝对路径,.js 后缀可以省略。
    如果只是模块名,不带路径,那么必须有配置文件来告诉JavaScript引擎该模块的位置。
    例如上面的 util 是模块文件名,由于不带有路径,必须是配置过的,告诉引擎怎么获取这个模块。

    02
    import命令输入的变量都是只读的,不允许在加载模块的脚本里面改写接口。

    import {a} from './xxx.js'
    
    a = {}; // Syntax Error : 'a' is read-only;
    a.foo = 'hello'; // 合法操作
    

    上面代码中,脚本加载了变量a,对其重新赋值就会报错,因为a是一个只读的接口。但是,如果a是一个对象,改写a的属性是允许的。
    第三行中a的属性被成功改写,并且其他模块也可以读到改写后的值。不过,这种写法很难查错,不建议这么做

    03
    import 语句是 Singleton 模式的。既同一个模块实例被 import 两次时,只会执行一次。

    04
    目前阶段,通过 Babel 转码,CommonJS 模块的require命令和 ES6 模块的import命令,可以写在同一个模块里面,但不建议这样做


    export default 命令

    export default 的写法如下:

    // 写法一
    export default function () { console.log('foo') }
    
    // 写法二
    export default function foo() { console.log('foo') }
    
    // 写法三
    function foo() { console.log('foo') }
    export default foo
    

    export default 命令可以使用匿名函数或非匿名函数。
    但是非匿名函数的的函数名在模块外是无效的。在模块外加载时视同非匿名函数来加载。

    01 export 和 export default 在输入上的不同

    // 第一组
    export function crc32() { // 输出
      // ...
    };
    import { crc32 } from 'crc32'; // 输入 当不用 as 时import 必须与 export 的名字相同
    
    
    // 第二组
    export default function crc32() { // 输出
      // ...
    }
    import c from 'crc32'; // 输入  可为该匿名函数指定任意名字
    

    对比上面两种写法可知,使用 export default 时, 对应的 import 语句不需使用大括号。
    这样的好处是当开发一些第三库时,用户未必愿意去了解模块有哪些属性和方法,这时为了用户方便,就可以用 export default 命令,为模块指定默认输出啦。

    02 export 和 export default在定义时的不同export default就是输出一个叫做default`的变量或方法

    // 正确
    export var a = 1;
    
    // 正确
    var a = 1;
    export default a;
    
    // 错误
    export default var a = 1;
    

    上面代码中,export default a的含义是将变量a的值赋给变量default。所以,最后一种写法会报错。

    同样地,因为export default命令的本质是将后面的值,赋给default变量,所以可以直接将一个值写在export default之后。

    // 正确
    export default 42;
    
    // 报错
    export 42;
    





    CommonJS 模块规范

    在 ES6 之前,社区指定了一些模块加载方案,主要的有 CommonJS 和 AMD 两种,前者用户服务器,后者用于浏览器。比如 CommonJS 模块是对象输出,输入时不需查找对象属性。

    ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。

    module.exports 与 require

    我们所熟悉的 NodeJS 由模块组成,采用的就是CommonJS 模块规范。

    CommonJS定义的模块分为: 模块标识(module)、模块定义(exports) 、模块引用(require)

    CommonsJS 规范规定,每个模块内部, module 变量代表当前模块。这个模块是一个对象,她的 exports 属性,来表示对外的接口(既 module.exports 是对外的接口)。
    例如

    var num = 5;
    var add = function (value) {
      return value + x;
    };
    module.exports.num  = num;
    module.exports.add = add;
    

    上面代码的输入格式如下:

    let { num, add } = require('util');
    
    // 或者
    let _util = require('util');
    console.log( _util.num ) //5
    console.log( _util.add(1) ) //6
    

    module.exports 与 exports

    为了方便,Node 为每一个模块提供一个 exports 变量,指向 module.exports。
    他们的关系是:
    exports = module.exports = {};

    • exports 是 module.exports 的一个引用,指向同一个内存地址;
    • module.exports 初始值为一个空对象{}, 所以 exports 初始值也是 {};
    • exports.xxx = 相当于在导出对象上挂属性,该属性对调用模块直接可见;
    • exports = 相当于给 exports 对象重新赋值,会切断了 exports 与 module.exports 的联系,所以建议使用 module.exports

    如果对上面说的一堆不理解,来看下面的例子:

    // requireMe.js
    // exports = function(){} // 错误写法 ,这样相当于直接给 exports 赋值
    exports.something = function(){  console.log('hello world') }
    // index.js
    var something = require('./requireMe');
    something();
    // 报错,因为 require 出来的 module.exports 是一个 object,不能直接执行
    
    
    //修改方式一
    // requireMe.js
    module.exports = function(){  console.log('hello world') }
    // 不报错,因为此时的 module.exports 是一个 function, 可以直接执行。
    
    
    // 修改方式二
    // index.js
    var something = require('./requireMe');
    something.something();
    // 因为这时候 require 出来的是一个 object,有一个 something 的属性,所以可以这样调用执行。
    



    参考文章:
    阮一峰:Module 语法
    liaofy:module.exports与exports,export与export default之间的关系和区别


    希望这篇文章能帮助到你
    END

    \color{#ccc}{liwuwuzhi}

    相关文章

      网友评论

          本文标题:Module 模块加载

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