• commonJs+AMD+CMD+ES6模块化


    nodejs

    安装nodejs
    官网地址:https://nodejs.org/zh-cn/

    浏览器运行的是html页面,并加载页面中通过script元素引入的js

    nodejs
    nodejs直接运行某个js文件,该文件被称之为入口文件
    nodejs遵循EcmaScript标准,但由于脱离了浏览器环境,因此:

    你可以在nodejs中使用EcmaScript标准的任何语法或api,例如:循环、判断、数组、对象等
    你不能在nodejs中使用浏览器的 web api,例如:dom对象、window对象、document对象等
    由于大部分开发者是从浏览器端开发转向nodejs开发的,为了降低开发者的学习成本,nodejs中提供了一些和浏览器web api同样的对象或函数,例如:console、setTimeout、setInterval等

    CommonJS

    在nodejs中,由于有且仅有一个入口文件(启动文件),而开发一个应用肯定会涉及到多个文件配合,因此,nodejs对模块化的需求比浏览器端要大的多

    由于nodejs刚刚发布的时候,前端没有统一的、官方的模块化规范,因此,它选择使用社区提供的CommonJS作为模块化规范

    在学习CommonJS之前,首先认识两个重要的概念:模块的导出和模块的导入

    模块的导出

    要理解模块的导出,首先要理解模块的含义

    什么是模块?

    模块就是一个JS文件,它实现了一部分功能,并隐藏自己的内部实现,同时提供了一些接口供其他模块使用

    模块有两个核心要素:隐藏和暴露

    隐藏的,是自己内部的实现
    暴露的,是希望外部使用的接口

    任何一个正常的模块化标准,都应该默认隐藏模块中的所有实现,而通过一些语法或api调用来暴露接口

    暴露接口的过程即模块的导出

    模块的导入

    当需要使用一个模块时,使用的是该模块暴露的部分(导出的部分),隐藏的部分是永远无法使用的。

    当通过某种语法或api去使用一个模块时,这个过程叫做模块的导入

    CommonJS规范
    CommonJS使用exports导出模块,require导入模块

    具体规范如下:

    如果一个JS文件中存在exports或require,该JS文件是一个模块
    模块内的所有代码均为隐藏代码,包括全局变量、全局函数,这些全局的内容均不应该对全局变量造成任何污染
    如果一个模块需要暴露一些API提供给外部使用,需要通过exports导出,exports是一个空的对象,你可以为该对象添加任何需要导出的内容
    如果一个模块需要导入其他模块,通过require实现,require是一个函数,传入模块的路径即可返回该模块导出的整个内容
    nodejs对CommonJS的实现
    为了实现CommonJS规范,nodejs对模块做出了以下处理

    为了保证高效的执行,仅加载必要的模块。nodejs只有执行到require函数时才会加载并执行模块

    为了隐藏模块中的代码,nodejs执行模块时,会将模块中的所有代码放置到一个函数中执行,以保证不污染全局变量。

     (function(){
         //模块中的代码
     })()
    
    • 1
    • 2
    • 3

    为了保证顺利的导出模块内容,nodejs做了以下处理

    在模块开始执行前,初始化一个值module.exports = {}
    module.exports即模块的导出值
    为了方便开发者便捷的导出,nodejs在初始化完module.exports后,又声明了一个变量exports = module.exports

     (function(module){
         module.exports = {};
         var exports = module.exports;
         //模块中的代码
         return module.exports;
     })()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    为了避免反复加载同一个模块,nodejs默认开启了模块缓存,如果加载的模块已经被加载过了,则会自动使用之前的导出结果

    浏览器端模块化的难题

    CommonJS的工作原理

    当使用require(模块路径)导入一个模块时,node会做以下两件事情(不考虑模块缓存):

    通过模块路径找到本机文件,并读取文件内容
    将文件中的代码放入到一个函数环境中执行,并将执行后module.exports的值作为require函数的返回结果
    正是这两个步骤,使得CommonJS在node端可以良好的被支持

    可以认为,CommonJS是同步的,必须要等到加载完文件并执行完代码后才能继续向后执行

    当浏览器遇到CommonJS

    当想要把CommonJS放到浏览器端时,就遇到了一些挑战

    浏览器要加载JS文件,需要远程从服务器读取,而网络传输的效率远远低于node环境中读取本地文件的效率。由于CommonJS是同步的,这会极大的降低运行性能
    如果需要读取JS文件内容并把它放入到一个环境中执行,需要浏览器厂商的支持,可是浏览器厂商不愿意提供支持,最大的原因是CommonJS属于社区标准,并非官方标准
    新的规范

    基于以上两点原因,浏览器无法支持模块化

    可这并不代表模块化不能在浏览器中实现

    要在浏览器中实现模块化,只要能解决上面的两个问题就行了

    解决办法其实很简单:

    远程加载JS浪费了时间?做成异步即可,加载完成后调用一个回调就行了
    模块中的代码需要放置到函数中执行?编写模块时,直接放函数中就行了
    基于这种简单有效的思路,出现了AMD和CMD规范,有效的解决了浏览器模块化的问题。

    AMD

    全称是Asynchronous Module Definition,即异步模块加载机制

    require.js实现了AMD规范

    在AMD中,导入和导出模块的代码,都必须放置在define函数中

    define([依赖的模块列表], function(模块名称列表){
        //模块内部的代码
        return 导出的内容
    })
    
    • 1
    • 2
    • 3
    • 4

    CMD

    全称是Common Module Definition,公共模块定义规范

    sea.js实现了CMD规范

    在CMD中,导入和导出模块的代码,都必须放置在define函数中

    define(function(require, exports, module){
        //模块内部的代码
    })
    
    • 1
    • 2
    • 3

    ES6导入导出

    基本导入导出
    模块的引入
    注意:这一部分非模块化标准

    目前,浏览器使用以下方式引入一个ES6模块文件

    <script src="入口文件" type="module">
    
    • 1
    模块的基本导出和导入

    ES6中的模块导入导出分为两种:

    基本导入导出
    默认导入导出

    基本导出

    类似于 exports.xxx = xxxx

    基本导出可以有多个,每个必须有名称

    基本导出的语法如下:

    export 声明表达式或export {具名符号}

    由于基本导出必须具有名称,所以要求导出内容必须跟上声明表达式或具名符号

    基本导入

    由于使用的是依赖预加载,因此,导入任何其他模块,导入代码必须放置到所有代码之前

    对于基本导出,如果要进行导入,使用下面的代码

    import {导入的符号列表} from “模块路径”

    注意以下细节:

    导入时,可以通过关键字as对导入的符号进行重命名
    导入时使用的符号是常量,不可修改
    可以使用*号导入所有的基本导出,形成一个对象

    默认导入导出

    默认导出

    每个模块,除了允许有多个基本导出之外,还允许有一个默认导出

    默认导出类似于CommonJS中的module.exports,由于只有一个,因此无需具名

    具体的语法是

    export default 默认导出的数据或export {默认导出的数据 as default}

    由于每个模块仅允许有一个默认导出,因此,每个模块不能出现多个默认导出语句

    默认导入
    需要想要导入一个模块的默认导出,需要使用下面的语法

    import 接收变量名 from “模块路径”
    类似于CommonJS中的

    var 接收变量名 = require("模块路径")
    
    • 1

    由于默认导入时变量名是自行定义的,因此没有别名一说

    如果希望同时导入某个模块的默认导出和基本导出,可以使用下面的语法

    import 接收默认导出的变量, {接收基本导出的变量} from "模块路径"
    注:如果使用*号,会将所有基本导出和默认导出聚合到一个对象中,默认导出会作为属性default存在
    
    • 1
    • 2
  • 相关阅读:
    常见场景面试题:BitMap、布隆过滤器
    云原生之容器编排实践-在CentOS7上安装使用Docker
    【算法每日一练]-图论(保姆级教程 篇3(遍历))#图的遍历 #奶牛牧场 #杂务
    mysql事务
    EPICS记录参考--sub-Array记录(subArray)
    Maven安装和配置详细教程
    RK3568平台开发系列讲解(音频篇)Audio 音量控制流程
    UDP协议之《传输队列长度sk_wmem_alloc统计》
    [管理与领导-113]:IT人看清职场中的隐性规则 - 10 - 看清人的行动、行为、手段、方法背后的动机与背景条件
    降级、熔断和限流———一看就会
  • 原文地址:https://blog.csdn.net/yehaocheng520/article/details/132811399