node.js 原理剖析
模块化概述
js 不是模块化编程语言,它不支持class
es6发布后 可以方便在js中使用类和模块了
-> 模块化规范
浏览器端规范
AMD(require.js)遵循的AMD规范(同步执行)
CMD(Sea.js) 遵循的CMD规范
ES6
服务器端规范
CommonJS(Node.js是CommonJS的实现)
Node的应用是由模块组成的
CommonJS特点
所有代码运行在当前模块作用域,不会污染全局作用域
模块同步加载,根据代码执行顺序载入
模块可多次加载,只会在第一次加载的时候运行一次,运行结果被缓存
以后再次加载模块,会直接从缓存中读取数据
module对象详解
module001.js let name = 'eval' let getName = function (name) { console.log(name); } // 模块导出,暴露在外面 module.exports = { name: name, getName: getName, } person.js // 引入 module001.js let person = require('./module001.js') console.log(person) // 终端中当前目录执行node person.js person.getName('study163') // 修改name的值 person.name = 'updateName' console.log(person) // 终端中当前目录执行node person.js 模块分类 module对象的属性 id: 当前模块的id 唯一的; exports: 表示当前模块暴露给外部的值。 parent: 是一个对象,表示调用当前模块的模块。 children: 是一个对象,表示当前模块调用的模块。 filename: 模块的绝对路径。 paths: 从当前模块开始查找node_modules目录,然后依次进入到父目录,查找父目录下的node_modules目录;依次换代,直到根目录下的node_modules目录。 loaded: 一个布尔值,表示当前模块是否完全加载。 一直找,直到找到根目录 03module.js // 直接导出一个对象 module.exports = { name: 'evan', getName: function (name) { console.log(name) } } console.log(module) 核心模块 Node.js提供的模块,例如http模块,fs模块等, 核心模块 -----通过编译------二进制文件----node启动时部分核心加载到内存中,因此部分模块不需要手动加载,加载的比较快; 文件模块 自己编辑的模块;文件模块是按需加载,加载比较慢。 module.exports 与exports 都是引用类型变量,指向同一个内存地址,在node中开始都指向空对象 exports 通过形参的方式传入,直接赋值给形参引用,不能改变作用域外的值 module.exports就是为了角色exports直接赋值的问题而产生的 04.module.exports var module = { exports: {} } var exports = module.exports; function change(exports) { // 通过形参的方式传入的exports exports.name = 'evan'; // 下面的直接赋值是错误的,exports的作用域只有这个作用域中,如果这样赋值的话,exports指向的地址(重新指向的新的地址)和module.exports的指向地址就不一样了。 exports = { age: 18; } console.log(exports); } change(exports) console.log(module.exports) 而module.exports 是可以直接赋值的,因为它是外部传进来,而exports则不可以。 正确写法如下: let name = 'ab'; let text = 'cd'; module.exports = { name, text }; require方法详解 require方法传入的是模块标识符 路径分析 -> 文件定位 -> 编译执行 路径分析(模块标识符分析) 1.核心模块。 2. 以'.'或者'../'开始的相对路径文件模块,如果找不到在modules中找,不利于项目迁移。 3. 以'/'开始的绝对路径模块。 非路径形式的模块(直接字符串) 文件定位 扩展名分析 .js 、.node文件去找或java扩展 目标文件和包分析 o5-load.js 找课程资料查询 // 计算绝对路径 ... // 第一步 如果有缓存,取出缓存。 ... // 第二步 是否为内置模块。 ... // 第三步 生成模块实例,存入缓存(如果上面两步都没有找到,创建) ... // 第四步 加载模块 ... // 第五步 输出模块的exports属性 ... 查询路径js 找课程资料查询,一个模块必须有个package.json 和入口文件 index.js // 列出所有可能的后缀名: .js 、 .json 、.node // 如果是绝对路径就不再搜索 // 是否有后缀的目录斜杠 // 第一步 如果当前路径已经缓存中,就直接返回缓存 // 第二步 遍历所有路径 // 第三步 是否存在该模块文件 // 第四步 该模块文件加载后缀名,是否存在 // 第五步 目录中是否存在package.json // 第六步 是否存在目录名+ index + 后缀名 // 第七步 将找到的文件路径存入返回缓存,然后返回 // 第八步 提示文件不存在 // npm init 创建package.json 如果目录没有main字段且也没有index.js的话,就提示你什么也没有找到 // node 运行js node .js文件 var a = require('./module001.js') var b = require('./module001.js') console.log(a===b) true // 因为导出module.exports 多个同一个内容的话,第二次导出会读取缓存,所以是指向同一块地址 node.js 原理剖析 自定义模块和核心模块相同时,自定义模块加载失败
require方法详解