认真学习,认真记录,每天都要有进步呀!!!

加油叭!!!


一、Node中的模块系统

使用Node编写应用程序主要就是在使用

  1. EcmaScript
  • 和浏览器不一样的是,在Node中没有BOM、DOM
  1. 核心模块
  • 文件操作的fs
  • http服务的http
  • url路径操作模块
  • os操作系统信息
  1. 第三方模块
  • art-template
  • 必须通过npm来下载才可以使用
  1. 自己创建的模块
  • 自己创建的文件

二、什么是模块化

  1. 具有文件作用域(没有污染)
  2. 具有通信规则(即可以加载又可以导出)

三、CommonJS模块化

在Node中的JavaScript还有一个很重要的概念:模块系统

  1. 模块作用域

    与浏览器相比不是全局作用域,模块作用域,默认全局当中的所有成员不能被外部访问
  2. 使用 require() 方法来加载模块

    没有 script 标签,不能通过 script 标签来加载文件
  3. 使用 exports 接口对象来导出模块中的成员

四、加载与导出

  1. 加载require()

    语法:
var 自定义变量名称 = require('模块')

require 方法有两个作用:

(1) 加载文件模块并执行里面的代码

(2)得到被加载文件模块导出的接口对象

  1. 导出exports()

Node中是模块作用域,默认文件中所有的成员只在当前文件模块有效

对于希望可以被其他模块访问的成员,我们就需要把这些公开的成员都挂载到exports接口中就可以了

在每个文件模块中都提供了一个对象:exports

exports 默认是一个空对象

你要做的就是把所有需要被外部访问的成员挂载到这个 exports 对象中

2.1 导出多个成员

exports.age = 123
exports.hi= 'hello'
exports.func = function(){
console.log('aaa')
}
exports.message={
name:'zs'
}

也可以这样来导出多个成员

module.exports = {
add = function(){
return x + y
},
str:'hello'
}

2.2 导出单个成员,拿到的就是函数,字符串

module.exports = 'hello'

以下情况会覆盖

module.exports = 'hello'

//以这个为准,后者会覆盖前者
module.exports = function(x,y){
return x + y
}

五、exports与module.exports的原理解析

在 Node 中,每个模块内部都有一个自己的 module 对象

该 module 对象中,有一个成员叫:exports

 var module = {
exports: {
对象名:'对象内容',
方法名:function
}
}
//模块中还有一句
var exports = module exports
//默认在代码最后一句
//谁来require我,谁就得到module exports
return module exports

也就是说如果你需要对外导出成员,只需要把导出的成员挂载到 module.exports

main.js

var fooExports = require('./foo')
console.log(fooExports)

foo.js

 module.exports.test1 = 'hello'
module.exports.test2 = 'world'
module.exports.add = function (x, y) {
return x + y
}
module.exports.reduce = function (x, y) {
return x - y
}

foo.js相当于

 var module = {
exports: {
test1: 'hello',
test2: 'world',
add: function,
reduce:function,
}
}

执行main.js结果:



再添加一些exports对象与方法

foo.js

 module.exports.test1 = 'hello'
module.exports.test2 = 'world' exports.test3 = 'hi'
exports.test4 = 'node.js' module.exports.add = function (x, y) {
return x + y
}
module.exports.reduce = function (x, y) {
return x - y
} exports.a = function(a,b){
return a + b
}
exports.b = function(a,b){
return a + b
}

结果:

我们发现,exports == module.exports,两者一致,说明可以使用任意一方来导出接口成员

每次导出接口成员的时候都通过 module.exports.xxx = xxx 的方式很麻烦,点儿的太多了

所以,Node 为了简化操作,专门提供了一个变量:exports 等于 module.exports

exports相当于 module.exports的一个引用

console.log(exports == module.exports)  // true
exports.foo = 'bar'
//等价于
module.exports.foo = 'bar'

也就是说在模块中还有这么一句代码

var exports = module.exports

当一个模块需要导出单个成员的时候

直接给 exports 赋值是不管用的

栗子:


exports = 'hello'

是个空对象,什么都没有

一定要记住,最后 return 的是 module.exports

不是 exports

所以你给 exports 重新赋值不管用,

return module.exports

对比去理解的栗子:

没有给exports 重新赋值之前

栗子:

 exports.a = 123
// exports = {}
exports.foo = 'bar'



给exports 重新赋值后

栗子:

 exports.a = 123
exports = {}
exports.foo = 'bar'

给 exports 赋值会断开和 module.exports 之间的引用,重新赋值以后,跟原来没有关系,后面添加都不管用



exports的修改不影响module.export

栗子:

exports.a = 123
exports = {}
exports.foo = 'bar'
module.exports.b = 456
//module.export一直都没有变,所有可以导出 b:456
//exports的修改不影响module.export



module.exports 重新赋值会断开与exports的引用

栗子:

module.exports = 'hello'
exports.a = '123'

总结:

给 exports 赋值会断开和 module.exports 之间的引用

同理,给 module.exports 重新赋值也会断开

栗子:

// 这里导致 exports !== module.exports
module.exports = {
foo: 'bar'
}
// // 但是这里又重新建立两者的引用关系
exports = module.exports
exports.foo = 'hello'

结果:



栗子:

 //{foo: bar}
exports.foo = 'bar' // {foo: bar, a: 123}
module.exports.a = 123 // exports !== module.exports
// 最终 return 的是 module.exports
// 所以无论你 exports 中的成员是什么都没用
exports = {
a: 456
} // {foo: 'haha', a: 123}
module.exports.foo = 'haha' // 没关系,混淆你的
exports.c = 456 // 重新建立了和 module.exports 之间的引用关系了
exports = module.exports // 由于在上面建立了引用关系,所以这里是生效的
// {foo: 'haha', a: 789}
exports.a = 789

最终结果:



再加上一句:

// // 前面再牛逼,在这里都全部推翻了,重新赋值
// // 最终得到的是 Function
module.exports = function () {
console.log('hello')
}

结果:

归纳总结:

真正去使用的时候:

导出多个成员:exports.xxx = xxx

导出多个成员也可以:module.exports = { }

导出单个成员:module.exports

六、总结exports与module.exports的区别

  • 每个模块中都有一个 module 对象
  • module 对象中有一个 exports 对象
  • 我们可以把需要导出的成员都挂载到 module.exports 接口对象中
  • 也就是:moudle.exports.xxx = xxx 的方式
  • 但是每次都 moudle.exports.xxx = xxx 很麻烦,点儿的太多了
  • 所以 Node 为了你方便,同时在每一个模块中都提供了一个成员叫:exports
  • exports === module.exports 结果为 trues
  • 所以对于:moudle.exports.xxx = xxx 的方式 完全可以:expots.xxx = xxx
  • 当一个模块需要导出单个成员的时候,这个时候必须使用:module.exports = xxx 的方式
  • 不要使用 exports = xxx 不管用
  • 因为每个模块最终向外 return 的是 module.exports
  • exports 只是 module.exports 的一个引用
  • 所以即便你为 exports = xx 重新赋值,也不会影响 module.exports
  • 但是有一种赋值方式比较特殊:exports = module.exports 这个用来重新建立引用关系的

七、require方法加载规则

  1. 优先从缓存加载



结果:

  1. 判断模块标识
  • 核心模块

核心模块的本质也是文件

核心模块文件已经被编译到了二进制文件中了,我们只需要按照名字来加载就可以了

eg:

require('fs')

require('http')

  • 路径形式的文件模块(自定义模块)

路径形式的模块:

./ 当前目录,不可省略

../ 上一级目录,不可省略

/xxx 几乎不用

d:/a/foo.js 几乎不用

首位的 / 在这里表示的是当前文件模块所属磁盘根路径

.js 后缀名可以省略

require('./foo') 相当于 require('./foo.js')

  • 第三方模块

凡是第三方模块都必须通过 npm 来下载

使用的时候就可以通过 require('包名') 的方式来进行加载才可以使用

不可能有任何一个第三方包和核心模块的名字是一样的

第三方模块既不是核心模块、也不是路径形式的模块

先找到当前文件所处目录中的node_modules目录

node_modules/art-template

node_modules/art-template/package.json文件

node_modules/art-template/package.json 文件中的 main 属性

main 属性中就记录了 art-template 的入口模块

然后加载使用这个第三方包

实际上最终加载的还是文件

如果 package.json 文件不存在或者 main 指定的入口模块是也没有

node 会自动找该目录下的 index.js

也就是说 index.js 会作为一个默认备选项

如果以上所有任何一个条件都不成立,则会进入上一级目录中的 node_modules 目录查找

如果上一级还没有,则继续往上上一级查找

。。。

如果直到当前磁盘根目录还找不到,最后报错:

can not find module xxx

var template = require('art-template')

注意:我们一个项目有且只有一个 node_modules,放在项目根目录中,这样的话项目中所有的子目录中的代码都可以加载到第三方包

不会出现有多个 node_modules

总结模块查找机制

  1. 优先从缓存加载
  2. 核心模块
  3. 路径形式的文件模块
  4. 第三方模块

    node_modules/art-template/

    node_modules/art-template/package.json

    node_modules/art-template/package.json main

    index.js 备选项

    进入上一级目录找 node_modules

    按照这个规则依次往上找,直到磁盘根目录还找不到,最后报错:Can not find moudle xxx

    一个项目有且仅有一个 node_modules 而且是存放到项目的根目录

参考详细文档: 深入Node.js的模块机制

八、npm

node package manager

  1. npm 网站 : https://www.npmjs.com/

    可以用来搜索第三方包

  2. npm命令行工具

    npm的第二层含义就是命令行工具,只要你安装了node 就相当于安装了npm

    npm 也有版本的这个概念

    查看npm版本
npm --version

升级npm版本

npm install --global npm
  1. npm 常用命令

    详细参考文档:https://www.cnblogs.com/PeunZhang/p/5553574.html
  2. 解决npm被墙的问题

    参考文档:https://blog.csdn.net/qq_45103612/article/details/108569090

九、package.json

建议每一个项目都要有一个package.json (包描述文件,就像产品说明书一样)

这个文件可以通过npm init的方式初始化出来



  • 建议每个项目的根目录中都有一个package.json文件
  • 建议执行npm install 包名的时候都加上 --save这个选项,目的是用来保存依赖项信息
  • 可以在package.json文件中通过dependencies选项,查看第三方包的依赖信息
  • 如果项目中的node_modules项目丢失了,只要 package.json文件存在,我们只需要npm install,就会自动把package.json中的dependencies中的所有依赖项都下载回来

十、package.json与package-lock.json

npm5以前是不会有package.json这个文件的

npm5以后才加入了这个文件

当你安装包以后,npm都会自动安装package-lock.json这个文件

  • npm5以后的版本安装包不需要加上--save参数,它会自动保存依赖信息
  • 当你安装包的时候,会自动创建或更新package-lock.json这个文件
  • package-lock.json会保存node_modules中所有包的信息(版本,下载地址)
  • 这样的话重新npm install的速度就会提升很多
  • 从文件来看,有一个lock称之为锁
  • 这个lock是用来锁定版本的
  • 如果这个项目依赖了1.1.1版本
  • 如果你npm install其实会下载最新版,而不是1.1.1
  • 所以package-loca.json的另外一个作用就是锁定版本号,防止自动升级新版

Node.js学习笔记----day03的更多相关文章

  1. 一点感悟:《Node.js学习笔记》star数突破1000+

    写作背景 笔者前年开始撰写的<Node.js学习笔记> github star 数突破了1000,算是个里程碑吧. 从第一次提交(2016.11.03)到现在,1年半过去了.突然有些感慨, ...

  2. Node.js学习笔记(3):NPM简明教程

    Node.js学习笔记(3):NPM简明教程 NPM常用操作 更新NPM版本 npm install npm -g -g,表示全局安装.我们可以指定更新版本,只需要在后面填上@版本号即可,也可以输入@ ...

  3. 系列文章--Node.js学习笔记系列

    Node.js学习笔记系列总索引 Nodejs学习笔记(一)--- 简介及安装Node.js开发环境 Nodejs学习笔记(二)--- 事件模块 Nodejs学习笔记(三)--- 模块 Nodejs学 ...

  4. Node.js学习笔记(2):基本模块

    Node.js学习笔记(2):基本模块 模块 引入模块 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很多编程语言都采用这种组织代码的方式.在No ...

  5. Node.js学习笔记(1):Node.js快速开始

    Node.js学习笔记(1):Node.js快速开始 Node.js的安装 下载 官方网址:https://nodejs.org/en/ 说明: 在Windows上安装时务必选择全部组件,包括勾选Ad ...

  6. Node.js学习笔记(4):Yarn简明教程

    Node.js学习笔记(4):Yarn简明教程. 引入Yarn NPM是常用的包管理工具,现在我们引入是新一代的包管理工具Yarn.其具有快速.安全.可靠的特点. 安装方式 使用npm工具安装yarn ...

  7. Node.js学习笔记(一)

    1.回调函数 node是一个异步事件驱动的平台,所以在代码中我们经常需要使用回调函数. 例: setTimeout(function(){ console.log('callback is calle ...

  8. Node.js学习笔记(一):快速开始

    最近接了一个node项目,虽然最后顺利完成了,但是由于第一次实战,整个过程是赶出来的,许多地方一知半解.现在项目结束了,就静下心来系统地学一学,理一理,读书不忘拿笔,既然读书了,当然就要记点东西.一方 ...

  9. Node.js学习笔记(一)基础介绍

    什么是Node.js 官网介绍: Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js us ...

  10. node.js学习笔记(三)——事件循环

    要理解事件循环,首先要理解事件驱动编程(Event Driven Programming).它出现在1960年.如今,事件驱动编程在UI编程中大量使用.JavaScript的一个主要用途是与DOM交互 ...

随机推荐

  1. 修改api-server支持的NodePort端口映射范围

    创建svc资源报错显示:provided port is not in the valid range. The range of valid ports is 30000-32767 k8s集群默认 ...

  2. 真正“搞”懂HTTP协议04之搞起来

    前两篇文章,我们从空间和时间的角度都对HTTP有了一定的学习和理解,那么基于上一篇的HTTP发展的时间顺序,我会在后面的文章由浅入深,按照HTTP版本内容的更迭,一边介绍相关字段的使用方法,一边讲解其 ...

  3. iOS逆向之某多多App抓包

    阅读此文档的过程中遇到任何问题,请关注公众号[移动端Android和iOS开发技术分享]或加QQ群[309580013] 1.目标 由于某多多App现使用longlink进行数据传输,使用charle ...

  4. SpringBoot使用@Async的总结!

    一些业务场景我们需要使用多线程异步执行任务,加快任务执行速度. 之前有写过一篇文章叫做: 异步编程利器:CompletableFuture 在实际工作中也更加推荐使用CompletableFuture ...

  5. i春秋时间

    打开题目就是一段php代码 大致的意思是 ------------------------------------------------------------------------------- ...

  6. ATM项目详解

    内容概要: ATM项目 代码实操流程 ATM项目 # 需求: """ - 额度15000或自定义 - 支持多账户登录 - 可以查看账户余额 - 可以提现(可自定义手续费比 ...

  7. 轻松玩转sed

    sed处理文本方法 1.文本或管道输入 2.读入一行到模式控件 3.sed命令处理 4.输出到屏幕 所以 sed是一个流处理编辑器 sed一次处理一行内容 sed不改变文件内容(可以通过重定向改变文件 ...

  8. Blender修改视野范围

    首先,我不是专门的建模人员.但是有时候会拿到建模人员的制作的模型导入进行修改. 比如简单的删除某个模型,调整模型的尺寸. 还有就是调整模型的建模中心点,这点有时候显得特别重要,模型的中心点偏离较大会给 ...

  9. 数电第8周周结_by_yc

    基本知识: 1.有限状态机的分类: Moore型:输出仅与电路的状态有关: Mealy型:输出与当前电路状态和当前电路输入有关. 2.有限状态机的描述方法: 状态转换图:节点:状态(Moore输出): ...

  10. JDK中内嵌JS引擎介绍及使用

    原文: JDK中内嵌JS引擎介绍及使用 - Stars-One的杂货小窝 最近研究阅读这个APP,其主要功能就是通过一个个书源,从而实现移动端阅读的体验 比如说某些在线小说阅读网站,会加上相应的广告, ...