首先我们要明白一个前提,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的区别
module和exports是Node.js给每个js文件内置的两个对象
在a.js中用exports或module.exports导出的对象,可以再另一个文件中通过该require()引用。
console.log(module.exports)//{}
console.log(exports) //{}
console.log(module.exports===exports) //true
实际上,这两个对象指向同一块内存,也就是说他们两个是等价的(不去改变他们指向的内存地址)
require引入的对象本质上是module.exports.当module.exports和exports指向的不是同一块内存,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