浅析commonjs中require的执行方式

239 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情

熟悉commonjs中的require到底在做一件什么事情?

1.require引入一个文件 2.执行文件中的内容 3.抛出一个module.exports

先看下面的代码,

//1.js

this.a = 1111
exports.b = 222
exports = {
    c:333
}
module.exports = {
    d:444
}
exports.e = 555
this.f = 666

//2.js
let res = require('./1.js')

1.js中的代码如果需要执行的话,是需要通过另一个文件对它进行require引用,从而执行内部的逻辑

即使单纯的在我们的编辑器中使用run来对代码进行编译的时候,也是通过nodejs实现一个临时文件的方式对1.js来进行require的引用

function require(path){
    ....
    //require内部 真正在运行引入文件(模块)的代码
    function _require(exports,require,module,__filename,__dirname){
        //1.js的代码在这里执行
    }
    var module = { //这个对象很重要 _require的
        exports:{}
    }
    var exports = module.exports //获取在1.js中返回的对象
    _require.call(exports,exports,require,module,__file,dirname)  //将_require函数用call指定到1.js返回的对象中执行
    ...

return  module.exports

}

从模仿require内部的实现函数来看,require其实是一个函数,通过reuqire引入的文件会执行在_require的内部中执行,_require传入5个参数,这也是我为什么在commonjs中能够使用exports、module.exports的原因

如何使用_require.call来改变this的指向,通过var exports = module.exports,指向的是module中的exports,并且传入的参数也是它,当this的指向改变时,那么在1.js中执行下面的代码

//1.js
this == module.exports //true
this== exports //true
...

当且仅当一开始的时候,this和moudle.exports和exports都是同一个东西

当执行1.js的时候,this,module.exports,exports三个被赋上了不一样的值

//1.js
this.a = 1111
exports.b = 222
exports = {
    c:333
}
module.exports = {
    d:444
}
exports.e = 555
this.f = 666

console.log(this)
console.log(exports)
console.log(module.exports)
//{ a: 1111, b: 222, f: 666 }
//{ c: 333, e: 555 }
//{ d: 444 }



//2.js
let res = require('./2.js')
console.log(res)
//{ d: 444 }

从2.js中的require引用文件来看,无论是在a中写了this、exports、module.exports,最终的返回结果只会是module.exports中的内容

因为在_require中返回的是return module.exports所以我们最终的结果是module.exports中的内容,无论有其他的exports抛出