Common JS 模块化

首先我们要明白一个前提,CommonJS模块规范和ES6模块规范完全是两种不同的概念。

我们知道在浏览器环境中,使用var声明一个全局变量会把该变量挂载到window对象上去,所以我们才可以访问到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环境中呢?
如果我们在一个js文件中直接打印window是找不到这个顶层对象的,因为node环境下的顶层对象是global,
那我们声明的全局变量会不会像window对象一样挂载到global对象上呢?下面我们来试一下。

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

我们要想把变量a挂载到global对象上就必须要这样做

//a.js文件
global.a=1;
console.log(global.a)
//注意:挂载到global对象上的属性也可以在其他文件被访问到(要先引入)
//b.js文件
reuqire('./a.js')
console.log(global.a)

但是为什么会是undefined呢?
这就涉及到了模块化,在node环境中会存CommonJS模块化,它会把当前的文件当成模块的方式加载,那怎么理解以模块的方式加载呢?
我们可以简单的认为,每一个模块就是一个函数,模块中的内容就相当于是函数中的内容。

this指向问题

我们再想另一个问题,既然模块是一个函数,函数里的this指向是什么呢?
我们知道函数中的this是指向调用它的对象的,然而每个模块又是一个函数,node环境中的this又不能指向window,那会是指向谁呢?经过试验,发现node环境下的this指向的是一个空对象,这是因为node环境下的this指向的其实就是该模块导出的对象,默认是一个空对象

console.log(this)  //{}
console.log(this === module.exports)  //true
console.log(this===exports)  //true
  //module.exports和exports是js内置的两个对象,后面会详细解释

那我们如何让this指向全局对象global呢?很简单,把内容放到一个自执行函数里面就可以了,因为自执行函数里面的this永远指向全局对象

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

argument问题

函数都会有arguments参数列表,而模块作为一个函数它的arguments又是什么呢?

//a.js
console.log(arguments)
//会打印出这么一大堆
[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'
}
//因为每个模块都是一个函数,由此我们可以推断出函数的形参
function(module.exports,require,module,__filename,__dirname){
//参数注:module.exports={}  导出的对象
//            require  引入的方法
//            module  module对象
//            __filename  文件路径
//            __dirname   文件夹路径
}

module.exports和exports的区别

moduleexports是Node.js给每个js文件内置的两个对象
a.js中用exportsmodule.exports导出的对象,可以再另一个文件中通过该require()引用。

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

实际上,这两个对象指向同一块内存,也就是说他们两个是等价的(不去改变他们指向的内存地址)
require引入的对象本质上是module.exports.当module.exportsexports指向的不是同一块内存,exports导出的内容就会失效。

//a.js
module.exports={name:'xxx'}
exports={name:'ssss'}  //同一个引用被修改,导出内容会失效
//可以用这种写法   exports.name='sss'

//b.js
let obj=require('./a.js')
console.log(obj.name)  //xxx
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容