js模块化

后端的commonjs规范

一. nodejs中, 只能有一个入口文件, 即启动文件. 在开发时候, 需要尽可能细致的分多个文件, 就产生了模块化规范的要求.

二. 模块化有两个核心要素: 隐藏和暴露;

 1. 有导入和导出的文件叫模块.

 2. 模块内的所有代码都是隐藏的, 不会污染全局.

 3. 导出: 将模块化的内容暴露的过程就是导出.

 4. 导入: 获取导出内容的过程

三. commonjs的导入导出

  1.导出:

 文件内的代码相当于放到一个立即执行函数中

如:

//a.js模块
const
c = 3; module.exports = { a: 1, b: 2, c: c }
模块中的代码, 放到上面的立即执行函数内, 导出的结果{a:1,b:2,c:3};

 注意: 导出的最终结果是module.exports, 而不是exports. 

          因此, exprots改变指针指向, 并不会造成导出内容的变化.

  2.require导入

       导入的结果是导出的结果. 

       模块缓存: 第一次导入会加载文件, 然后执行文件, 将执行后的内容存到一块缓存区域里

                     下次导入文件前, 先检查模块缓存中是否存在,

                                                   如果存在, 会直接从缓存中取,

                                                    如果不存在, 才去加载文件执行文件获取导出结果.

commonjs的执行过程, 或者原理就是:

         1.用nodejs读取文件,

         2. 将文件作为立即执行函数的执行内容

         3. 返回module.exports的值.


前端过渡阶段的amd和cmd

一: 为什么在浏览器不能用commonjs规范.

     1.由于commonjs中require函数的执行是同步的;

      2. 浏览器到服务器获取是通过网络请求, 与commonjs中用nodejs直接读取文件相比,  网络请求会慢的多. 失败风险也大的多. 会导致执行缓慢甚至堵塞.

二. 解决思路, 用异步回调代替commonjs的require

三. AMD规范: 

         define(["模块1","模块二"...], function(arg1, arg2){  //arg1和arg2分别对应模块1和模块2的返回值, 

            //等加载完所有模块, 该回调函数会执行

           } )

四. cmd规范:

        define(function(require, exports, module){

        //用require导入,

        })

     可以看出, cmd为了方便开发人员, 将后端nodejs的api习惯带入了前端模块化.


es6模块化

commonjs的导入;

1.依赖延迟声明, 优点是某些条件下能够减少模块加载量,

比如: if(xx){require("./a.js")}else{require("./b")}这样就会少加载一个文件,而不是a  b两个文件都加载

      2.导入路径./或../开头 与直接写文件名含义不一样;

es6的导入导出特点:

      1.依赖预声明:,优点是依赖关系明确, 上来就能看到引入的所有模块, java, c语言都用这种导入模式.

       2.规范的路径表示方法: 必须以./或者 ../开头, 不能直接写文件名.

       3.灵活多样导出方式和导入方式.

导入导出分基本导入导出和默认导入导出;

            基本导入导出和默认导入导出二者可以同时存在

            基本导入导出可以有多个, 默认导入导出只能有一个

            基本导入导出因为有多个, 所以必须具名. 即后面必须用表达式, 默认导出只有一个, 所以不需要.

基本导出语法: 

       1.export 声明表达式:  

              export var  a=1;

       2. export {变量}

               var a = 1; export {a}; //相当于 导出的名字是a, 值是1. 

               注意: export a是错误的.

基本导入语法: 

       1. 导入其中某个或某几个模块的值,

               import {a  [as  xx]} from "a.js";   

        2.导入所有值. 

              import * as obj from "a.js"

注意. 导入的值禁止更改. 是一个常量值.   

默认导出: 

         export default xx;   //xx可以是变量名, 字符串, 对象等

默认导入

         import a from "/a.js"   表示将a.js里的默认导出赋值给常量a

         import * as data from "a.js";  //data里有{default: xx, 基本导出} 

注意: 导出的数据是常量, 最好用const声明. 

es6导出和commonjs导出的结果有什么不一样:es6的导出结果不能更改,而commonjs导出结果可以更改的

如果用es6导入后更改,会报错

1、CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。

2、所谓值的拷贝,原始类型的值被缓存,不随模块内部的改变而改变。

3、ES6 模块是动态引用,不缓存值,模块内外是绑定的,而且是只读引用,不能修改值。ES6 的 js 引擎对脚本静态分析的时候,遇到加载命令模块 import ,就会生成一个只读引用,当真正用到模块里边的值的时候,就会去模块内部去取。

4、CommonJS 模块是运行时加载,ES6 模块是编译时加载输出接口。

5、运行时加载:CommonJS 模块就是对象;是先加载整个模块,生成一个对象,然后再从这个对象上面读取方法,这种加载称为“运行时加载”。
6、编译时加载: ES6模块不是对象,而是通过 export 命令「显式指定输出的代码」。import 时采用静态命令的形式,即在import指定「加载某个输出值」,而「不是加载整个模块」,这种加载称为“编译时加载”。

7、import的接口是read-only(只读状态),不能修改其变量值。 即不能修改其变量的指针指向,但可以改变变量内部指针指向,可以对commonJS对重新赋值(改变指针指向),但是对ES6 Module赋值会编译报错。

原文地址:https://www.cnblogs.com/dangdanghepingping/p/14479898.html