模块化
seajs
--CMD(就近依赖,只有用到才会导出,浏览器端)requirejs
--AMD(前置依赖,浏览器端)commonJS
--node(服务器端)
commonjs
node自带模块化功能,一个js文件就是一个模块,模块this不是global,实现基础是闭包。
模块引用时会找到绝对路径
模块加载过会有缓存,把文件名作为key,module作为value
node实现模块化就是增加了一个闭包,并且自执行这个闭包
模块加载时是同步操作
默认会加后缀js,json,node
不同模块下的变量不会相互冲突
//全局对象,在任意的地方都可以使用,不经过任何声明就可以使用
//浏览器(在浏览器里面,全局对象global是一个概念,其具体的反映就是window)
console.log(this === window) //true
//node(在node里面,全局对象global具像化了,真正指代全局对象)
//1. 文件里
console.log(this) //{}
//2. 命令行里
console.log(global) // ...
// => node文件中的this不是global
闭包
//node
console.log(this)
var a = 1
console.log(this.a) //undifined
a = 1
console.log(global.a) //在这个文件环境里面找不到a就会向上找到全局global, a=1
//类似于
var a = 1
function(){
a = 1
console.log(global.a)
}
//模块对应的闭包函数的参数
console.log(arguments)
导出文件的具体实现
//exports内存中指向的就是module.exports指向的那块空间
//require一个方法
//Module模块类
//__filename该文件绝对路径
//__dirname该文件父文件夹的绝对路径
(function(exports,require,Module,__filename,__dirname){
module.exports = exports = this = {}
//文件中的所有代码
//不能改变exports指向,因为返回的是module.exports,所以是个{}
return module.exports
})
所以我们require的时候其实就相当于执行了这么一个闭包,然后返回的就是我们的module.exports。
require是怎么样的?
- 每个模块都会带一个require方法
- 动态加载(v8执行到这一步才会去加载此模块)
- 不同模块的类别,有不同的加载方式,一般有三种常用后缀
– 后缀名为.js的JavaScript脚本文件,需要先读入内存再运行
– 后缀名为.json的JSON文件,fs 读入内存 转化成JSON对象
– 后缀名为.node的经过编译后的二进制C/C++扩展模块文件,可以 - 查找第三方模块
– 如果require函数只指定名称则视为从node_modules下面加载文件,这样的话你可以移动模块而不需要修改引用的模块路径。
第三方模块的查询路径包括module.paths和全局目录。
关于闭包
js权威指南
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f;
}
var foo = checkscope();
foo();
作用域链
f = { Scope: [AO, checkscope, global] }
就是因为这个作用域链,f 函数依然可以读取到 checkscope.AO
的值,说明当 f 函数引用了 checkscope.AO
中的值的时候,即使 checkscope
被销毁了,但是 JavaScript 依然会让checkscope.AO
活在内存中,f 函数依然可以通过 f 函数的作用域链找到它,正是因为 JavaScript 做到了这一点,从而实现了闭包这个概念。
即使创建它的上下文已经销毁,它仍然存在(比如,内部函数从父函数中返回)