• CommonJs/ES6/AMD模块的用法以及区别


    转自:https://www.cnblogs.com/chinabin1993/p/10565816.html

    github地址:
    一直以来对CommonJs/AMD/CMD/ES6的文件模块加载一直懵懵懂懂。甚至有时会将CommonJs的exports和ES6的export.default搞混。趁着学习webpack,先搞懂这些模块加载方式再说!!!

    随着前端的发展,我们日常开发的功能越来越复杂,文件越来越多。随后前端社区衍生出了CommonJs/AMD/CMD/ES6的几种模块加载方式。

    模块加载方式

    1. CommonJs
    2. ES6
    3. AMD
    4. CMD

    01: CommonJs

    参考地址:阮一峰老师讲解的CommonJs规范
    每个文件都是一个单独的模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。
    CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(即module.exports)是对外的接口。加载某个模块,其实是加载该模块的module.exports属性。

    CommonJs的特点
    1. 所有的代码都运行在模块作用域,不会污染全局作用域;
    2. 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行的结果就会被缓存了,以后再加载就直接读取缓存结果。要想让模块继续运行,必须清空缓存;
    3. 模块加载顺序,按照其在代码中出现的顺序;
    4. CommonJs加载模块是同步的;
    Module对象

    我们在demo01中创建两个js文件,名为c1.js,main.js
    c1.js
    每个模块内部都有一个module对象,代表当前模块。它有以下属性:

    • module.id 模块的识别符,通常是带有绝对路径的模块文件名。
    • module.filename 模块的文件名,带有绝对路径。
    • module.loaded 返回一个布尔值,表示模块是否已经完成加载。
    • module.parent 返回一个对象,表示调用该模块的模块。
    • module.children 返回一个数组,表示该模块要用到的其他模块。
    • module.exports 表示模块对外输出的值。
    console.log(module);
    

    在命令行中执行

    node c1.js
    

    输出结果为

     Module {
      id: '.',
      exports: {},
      parent: null,
      filename: '/Users/Desktop/demo01/c1.js',
      loaded: false,
      children: [],
      paths:
       [] }
    

    其中主要关注的是module.exports这个属性,它表示当前模块对外输出的接口,其他文件加载该模块,实际上就是读取module.exports变量。

    注意:一下都在node环境中执行,也就是使用命令行node xxx.js 来执行的因为CommonJs是在node环境中运行的。

    创建一个c2.js文件

    c2.js
    创建一个对象c2,通过module.exports把该对象暴露,在main.js中,使用require进行接收。

    let c2 = {
      num: 5,
      sum: function(a,b){
        return a+ b
      },
      person: {
        name: 'wbin',
        age: '25'
      }
    }
    module.exports = c2;
    

    main.js

    let c2 = require('./c2');
    console.log(c2); // { num: 5,sum: [Function: sum],person: { name: 'wbin', age: '25' } }
    

    如果要暴露具体内容
    创建c3.js

    c3.js

    let c3 = {
      num: 5,
      sum: function(a,b){
        return a+ b
      },
      person: {
        name: 'wbin',
        age: '25'
      }
    }
    
    module.exports.num = c3.num;
    module.exports.person = c3.person;
    

    main.js

    let {num, person} = require('./c3');
    console.log(num, person); // 5 { name: 'wbin', age: '25' }
    

    c3.js中,我暴露出c3对象的两个属性,numperson,在main.js中使用了ES6的对象扩展来接收对应的值。

    module.exportsexports(这点只需要了解即可,在开发过程中,建议使用module.exports

    为了方便,Node为每个模块提供一个exports变量,指向module.exports。这等同在每个模块头部,有一行这样的命令

    var exports = module.exports;
    

    但是需要注意的是,不能直接将exports变量指向一个值,这种行为相当于切断了exportsmodule.exports的关系

    在demo01中创建c4.js
    c4.js

    let c4 = {
      num: 5,
      sum: function(a,b){
        return a+ b
      },
      person: {
        name: 'wbin',
        age: '25'
      }
    }
    exports = c4;
    

    main.js

    let c4  = require('./c4');
    console.log(c4); // {}
    

    以上输出结果是无效的,是一个空对象。
    正确的写法是
    c4.js

    let c4 = {
      num: 5,
      sum: function(a,b){
        return a+ b
      },
      person: {
        name: 'wbin',
        age: '25'
      }
    }
    exports.c4 = c4;
    

    为了防止这种不必要的错误,建议使用module.exports

    02: ES6

    参考地址:《ES6入门》第22和23章

    ES6模块的设计是尽可能的静态化,使得编辑时就能确定模块之间的依赖关系,以及输入和输出变量。而CommonJs和AMD则是在运行时才能实现以上结果。
    例如CommonJs模块就是一个对象,输入时必须查找对象属性,而ES6模块则可以暴露出任何变量、函数等。

    所以说ES6模块的加载方式是“编译时“加载或者是静态加载。

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

    demo02e1.js
    可以使用export暴露变量

    var firstName = 'w';
    var lastName = 'bin';
    var year = 1993;
    
    export {firstName, lastName ,year};
    
    

    也可以暴露fun

    export function mul(a, b){
      return a * b;
    }
    

    一般情况下,export输出的变量就是本来的名字,但是可以使用as进行重命名。进行重命名之后我们可以给某个变量(可能是fun)这些进行多次输出。

    function add(a, b){
      return a + b;
    }
    function reduce(a, b){
      return a - b;
    }
    export {
      add as sum,
      reduce as mius,
      reduce as jian
    }
    

    需要注意的是:ES6模块的import/export目前不支持在node环境中直接使用,可以使用webpack打包之后在浏览器中查看效果

    使用import来加载某个模块
    e2.js

    export let name = 'wbin';
    export let age = 26;
    

    main.js

    import {name, age} from './e2';
    console.log(name, age);
    

    import命令接收一个大括号{},里面指定要从其他模块加载的变量名。需要注意的是加载的变量名必须和export输出的变量名一致。但是我们可以在improt中给该名称重新命名。

    import {name as wbin, age} from './e2';
    console.log(wbin, age);
    

    有时我们需要整体加载所需要的模块,可以使用*号来加载

    circle.js

    export function area(radius) {
      return (Math.PI * radius * radius);
    }
    export function circumference(radius){
      return 2 * Math.PI * radius;
    }
    

    main.js

    // 整体引入
    import * as circle from './circle';
    console.log(circle.area(2),circle.circumference(2));
    
    默认输出 export default

    e3.js

    export default function(){
      return '123'
    }
    

    main.js

    import name from './e3';
    console.log(name()); // 123
    

    注意:使用默认输出时,import不使用{},使用正常输出时,import需要使用{}!!!

    03: AMD

    AMD是"Asynchronous Module Definition"的缩写,意思就是"异步模块定义"。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。

    AMD也采用require()语句加载模块,它要求两个参数:

    require([module], callback);
    

    在demo03文件夹中创建几个文件 index.html,main.js,sum.js,all.js以及简单的webpack配置 webpack.config.js

    webpack.config.js

    module.exports = {
      entry: {
        bundle: './main.js'
      },
      output: {
        filename: '[name].js'
      },
      mode: 'development'
    }
    

    sum.js

    define(function(){
      return {
        sum: function(a, b){
          return a + b;
        }
      }
    })
    

    main.js

    require(['./sum'],function(sum){
      console.log(sum.sum(1,2));
    })
  • 相关阅读:
    “不裁员”才是公司度过艰难时期的聪明选择
    oracle服务端与客户端字符集不同导致中文乱码解决方案
    [转]ABAP数据库操作系列(5)
    [转]ABAP数据库操作系列(2)
    [转]整理的函数
    [转]ABAP数据库操作系列(6)
    [转]ABAP数据库操作系列(7)
    [转]Authoritycheck
    [转]ABAP Program to Display SAP Icons
    [转]ABAP数据库操作系列(3)
  • 原文地址:https://www.cnblogs.com/jiduoduo/p/13502987.html
Copyright © 2020-2023  润新知