zhh10 / Notes

前端中react、Vue、ES6、css3、webpack、模块化等思维导图
12 stars 1 forks source link

commonJS与ES6模块化的区别 #13

Open zhh10 opened 4 years ago

zhh10 commented 4 years ago

ES6 与 commonJS的差异

  1. commonJS输出的值是值的拷贝,即原来模块中的值改变不会影响已经加载的该值,es6模块化是静态分析,动态引用,输出的是值的引用,值改变,引用也改变,即原来模块中的值改变,则该加载的值也改变。
    // lib.js
    let counter = 3 
    function addCounter(){
    counter++
    }
    module.exports = {
    counter:counter,
    addCounter:addCounter
    }
    // main.js
    let mod = require('./lib.js')
    console.log(mod.counter)
    mod.addCounter() 
    console.log(mod.counter)

    改进

    let counter = 3 
    function addCounter(){
    counter++ 
    }
    module.exports = {
    getCounter(){
        return counter
    },
    addCounter:addCounter
    }

    ES6模块化

    // lib.js
    export let counter = 3 
    export function addCounter(){
    counter++
    }
    // main.js
    import {counter,addCounter} from './lib.js'
    console.log(counter) //3 
    addCounter() 
    console.log(coutner) //4
  2. commonJS模块是运行时加载,es6模块是编译时输出接口。
  3. commonJS加载的是整个模块,即将所有的接口全部加载进来,es6可以单独加载其中某个接。
  4. commonJS中的this指向当前模块,es6模块化的this指向undefined。

es6模块化运行机制与commonJS不一样,JS引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块去取值,es6模块化不会缓存运行结果,而是动态地去加载的模块取值,而且变量总是绑定在其所在的模块。

commonJS 规范

Node在解析JS模块时,会先按文本读取内容,然后将模块内容进行包裹,在外层包裹了一个function,传入变量。

commonJS规范是在代码运行时同步阻塞地加载模块,在执行代码过程中遇到require(X)会停下来等待,直到新的模块加载完成后再继续执行接下来的代码。

function require(modulePath){
    //1. 将modulePath转化为绝对路径
    // D:\Users\NodeJS\myModule.js
    // 2. 判断是否该模块已经有缓存
    if(require.cache["D:\User\NodeJS\myModule.js"]){
        return require.cache["D:\User\NodeJS\myModule.js"]
    }
    // 3. 读取文件内容
    // 4. 包裹到一个函数中
    function _temp(module,exports,require,__dirname,__filename){
        console.log("当前模块路径",__dirname)
        console.log("当面模块文件",__dirname)
        exports.c = 3 
        module.exports = {
            a:1,
            b:2
        }
        this.m = 5
    }
    // 5. 创建module对象
    module.exports = {} 
    const exports = module.exports 

    __temp.call(module.exports, module, exports, require, module.path, module.filename)

    return module.exports;
    }
    require.cache = {};

}

commonJS的缓存

文件查询挺耗时的,还有在实际开发中,模块可能包含副作用代码,例如在模块顶层执行addEventListener,如果require过程中被重复执行多次可能会出现问题。

commonJS中的缓存可以解决重复查找和重复执行的问题。以绝对路径为keymodule对象为value写入cache。在读取模块的时候会优先判断是否已在缓存中,如果在,直接返回module.exports,如果不在,则会进入模块查找的流程。

//a.js 
module.exports = {
    foo:1
}

// main.js
const a1 = require('./a.js')
a1.foo = 2;

const a2 = require('./a.js')

console.log(a2.foo) //2
console.log(a1 === a2) //true