Common JS 模塊化

首先我們要明白一個(gè)前提,CommonJS模塊規(guī)范和ES6模塊規(guī)范完全是兩種不同的概念。

我們知道在瀏覽器環(huán)境中,使用var聲明一個(gè)全局變量會(huì)把該變量掛載到window對(duì)象上去,所以我們才可以訪問(wèn)到window.a

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
</body>
<script>
    var a=1;
    console.log(window.a)  //  1
</script>
</html>

那如果是在node環(huán)境中呢?
如果我們?cè)谝粋€(gè)js文件中直接打印window是找不到這個(gè)頂層對(duì)象的,因?yàn)閚ode環(huán)境下的頂層對(duì)象是global,
那我們聲明的全局變量會(huì)不會(huì)像window對(duì)象一樣掛載到global對(duì)象上呢?下面我們來(lái)試一下。

var a=1;
console.log(global.a)  //undefined

我們要想把變量a掛載到global對(duì)象上就必須要這樣做

//a.js文件
global.a=1;
console.log(global.a)
//注意:掛載到global對(duì)象上的屬性也可以在其他文件被訪問(wèn)到(要先引入)
//b.js文件
reuqire('./a.js')
console.log(global.a)

但是為什么會(huì)是undefined呢?
這就涉及到了模塊化,在node環(huán)境中會(huì)存CommonJS模塊化,它會(huì)把當(dāng)前的文件當(dāng)成模塊的方式加載,那怎么理解以模塊的方式加載呢?
我們可以簡(jiǎn)單的認(rèn)為,每一個(gè)模塊就是一個(gè)函數(shù),模塊中的內(nèi)容就相當(dāng)于是函數(shù)中的內(nèi)容。

this指向問(wèn)題

我們?cè)傧肓硪粋€(gè)問(wèn)題,既然模塊是一個(gè)函數(shù),函數(shù)里的this指向是什么呢?
我們知道函數(shù)中的this是指向調(diào)用它的對(duì)象的,然而每個(gè)模塊又是一個(gè)函數(shù),node環(huán)境中的this又不能指向window,那會(huì)是指向誰(shuí)呢?經(jīng)過(guò)試驗(yàn),發(fā)現(xiàn)node環(huán)境下的this指向的是一個(gè)空對(duì)象,這是因?yàn)閚ode環(huán)境下的this指向的其實(shí)就是該模塊導(dǎo)出的對(duì)象,默認(rèn)是一個(gè)空對(duì)象

console.log(this)  //{}
console.log(this === module.exports)  //true
console.log(this===exports)  //true
  //module.exports和exports是js內(nèi)置的兩個(gè)對(duì)象,后面會(huì)詳細(xì)解釋

那我們?nèi)绾巫宼his指向全局對(duì)象global呢?很簡(jiǎn)單,把內(nèi)容放到一個(gè)自執(zhí)行函數(shù)里面就可以了,因?yàn)樽詧?zhí)行函數(shù)里面的this永遠(yuǎn)指向全局對(duì)象

//a.js
(function(){
  console.log(this)  //global  ...(注:...代表省略了其他一些屬性)
})()

argument問(wèn)題

函數(shù)都會(huì)有arguments參數(shù)列表,而模塊作為一個(gè)函數(shù)它的arguments又是什么呢?

//a.js
console.log(arguments)
//會(huì)打印出這么一大堆
[Arguments] {
  '0': {},
  '1': [Function: require] {
    resolve: [Function: resolve] { paths: [Function: paths] },
    main: Module {
      id: '.',
      path: 'D:\\Review',
      exports: {},
      parent: null,
      filename: 'D:\\Review\\test.js',
      loaded: false,
      children: [],
      paths: [Array]
    },
    extensions: [Object: null prototype] {
      '.js': [Function],
      '.json': [Function],
      '.node': [Function],
      '.mjs': [Function]
    },
    cache: [Object: null prototype] { 'D:\\Review\\test.js': [Module] }
  },
  '2': Module {
    id: '.',
    path: 'D:\\Review',
    exports: {},
    parent: null,
    filename: 'D:\\Review\\test.js',
    loaded: false,
    children: [],
    paths: [ 'D:\\Review\\node_modules', 'D:\\node_modules' ]
  },
  '3': 'D:\\Review\\test.js',
  '4': 'D:\\Review'
}
//因?yàn)槊總€(gè)模塊都是一個(gè)函數(shù),由此我們可以推斷出函數(shù)的形參
function(module.exports,require,module,__filename,__dirname){
//參數(shù)注:module.exports={}  導(dǎo)出的對(duì)象
//            require  引入的方法
//            module  module對(duì)象
//            __filename  文件路徑
//            __dirname   文件夾路徑
}

module.exports和exports的區(qū)別

moduleexports是Node.js給每個(gè)js文件內(nèi)置的兩個(gè)對(duì)象
a.js中用exportsmodule.exports導(dǎo)出的對(duì)象,可以再另一個(gè)文件中通過(guò)該require()引用。

console.log(module.exports)//{}
console.log(exports)  //{}
console.log(module.exports===exports)  //true

實(shí)際上,這兩個(gè)對(duì)象指向同一塊內(nèi)存,也就是說(shuō)他們兩個(gè)是等價(jià)的(不去改變他們指向的內(nèi)存地址)
require引入的對(duì)象本質(zhì)上是module.exports.當(dāng)module.exportsexports指向的不是同一塊內(nèi)存,exports導(dǎo)出的內(nèi)容就會(huì)失效。

//a.js
module.exports={name:'xxx'}
exports={name:'ssss'}  //同一個(gè)引用被修改,導(dǎo)出內(nèi)容會(huì)失效
//可以用這種寫法   exports.name='sss'

//b.js
let obj=require('./a.js')
console.log(obj.name)  //xxx
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容