Node.js下篇

4. 模块系统

4.1 Common.JS 模块规范

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

  • 模块作用域
  • 使用 require 方法来加载模块
  • 使用 exports 接口对象来导出模块中的成员

4.1.1 加载 require

语法:

const 自定义变量名称 = require('模块')

两个作用:
1.执行被加载模块中的代码
2.得到被加载模块中的exports,导出接口对像

4.1.2导出 exports

  • Node.js 中是模块作用域,默认文件中所有的成员都挂载到exports接口对象中就可以了
    1.导出多个成员*

    exports.a = 123;
    exports.b = 'hello';
    exports.c = function () {
    	console.log('ccc')
    };
    exports.d = {
    	foo:'bar'
    };
    

    2.(1)导出单个成员

    module.exports = 'hello';
    

    (2)以下这种情况会覆盖

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

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

    module.exports = {
    	add: function (x,y) {
    		return x + y
    	}
    	str: 'hello'
    }
    
//main.js文件

//默认的到的是对象
//使用对象中的成员时必须.点儿出来
//有时候,对于一个模块,我们仅仅就是希望导出其中的某一个成员
const fooExports = require('./foo');
console.log(fooExports)
//foo.js文件
const foo = 'bar';
function add (x,y) {
	return x + y; 
} 
//如果一个模块需要直接导出某个成员,而非一个对象
//那这个时候必须使用下面的这种方式
module.exports = add
//exports = add; 这种方法是不对的




//exports 是一个对象
//我们可以通过多次为这个对象添加成员实现对外导出多个
//只能得到我想要给你的成员
//这样做的目的是为了解决命名冲突的问题
//exports.add = add;
//你可以认为在每个模块的最后 return 了这个exports

4.1.3 exportsmodule-exports 的区别

原理解析
exportsmodule.exports 是一个引用

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

详细解析

  • node默认的一些东西
//在 node 中,每个模块内部都有一个自己的 module 对象
//该 module 对象中有一个成员叫: exports(也是一个对象)
//也就是说如果你需要对外导出成员。只需要把导出的成员挂载到 module.exports 中

const module = {
	exports: {
		
	}
}

//默认在代码最后有一句: return module.exports
return module.exports
//谁来 require 我,谁就得到 module.exports
//我们发现每次导出接口成员的时候都通过 module.exports.xxx = xxx 的方式很麻烦,点的太多
//所以为了简化操作专门提供了一个变量 module.exports = exports
//也就是说在模块中还有这样一句代码: const exports= module.exports
console.log(module.exports === exports)	//ture

module.exports.foo = 'bar';
module.export.add = function (x,y) {
	return x + y
}
//const module = {
//	exports: {
//		foo : 'bar',
//		add = function (x,y) {
//			return x + y
//		}
//	}
//}
//return module.exports
  • 一些注意事项
//当给一个模块需要导出单个成员的时候,直接给exports 赋值是不管用的
exports = 'hello'	//不可行


//一定要注意,最后 return 的是 module.exports,不是 exports ,所以给exports 重新赋值就丢失了两者之间的引用关系。
exports = {};
exports.foo = 'bar';
//这时所加载此文件的文件不会得到foo的值 

一个小栗子

exports.a = 'hello';	//有用
exports = {}//重新赋值,失去引用
exports.foo = 'bar';
module.exports.b = 'world'
//可以得到的有a 的值和 b 的值

重新建立引用

//给 exports 重新赋值会断开和 module.exports 之间的引用
//同理,给 module.exports 重新赋值同样会断开

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

//最后得到的是{foo:hello}

来个练习题

//{foo:bar}
exports.foo = 'bar';

//{foo:bar,a:123}
module.exports.a = 123;

//exports !== module.exports
//最终 return 的是 module.export
//所以无论你 exports 中的成员是什么都没用
export = {
	a:456
};

//{foo:hahaha,a:123}
module.exports.foo = 'hahaha';

//没关系,混淆你的
exports.c = 456;

//重新建立引用关系
exports = module.exports;

//因为前面重新建立了关系,所以这里是有用的
//{foo: 'hahaha', a:789}
export.a = 789;

//前面再nb这里也重新赋值
//最终得到的是 Function
module.exports = function () {
	console.log('hello')
}

//真正去使用的时候
//		导出多个成员exports.xxx = xxx;
//		导出多个成员也可以: module.exports = {};
//		导出单个成员: module.exports

//当然你可以只使用 module.exports ,避免混淆

4.1.4 require方法加载规则

1. 优先从缓存加载

//main.js 文件

require('./a');
//优先从缓存加载
//由于在 a 中已经加载过 b ,所以这里不会重复加载
//可以拿到其中的接口对象
//这样做的目的是为了避免重复加载,提高模块加载效率

const fn = require('./b');
console.log(fn)


//最后结果是
//a.js被加载了
//b.js被加载了
//[Function]
//[Function]
//a.js文件
console.log('文件被加载了');
const fn = require('./b');
console.log(fn);
//b.js文件

console.log('b被加载了');

module.exports = function () {
	console.log('hello bbb');
}

require
* 如果是非路径形式的模块标识
路径形式模块:
./ 当前目录,不可省略
…/ 上一级目录,不可省略
/xxx 几乎不用
D;/a/faa.js 几乎不用
首位的 / 在这里表示的是当前文件模块所属磁盘根路径
.js后缀名可以省略
require('./foo.js')
2. 核心模块的本质也是文件
核心模块文件已经被编译到了二进制文件中了,我们只需要按照名字来加载就可以了
require('fs') require('http')
3. 第三方模块

  • 凡是第三方模块都必须通过 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 目录查找,如果上一级还没有,则继续往上上一级查找,如果直到当前磁盘根目录还找不到,最后报错

  • 注意:我们一个项目中有且只有一个 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
    按照这个规则依次往上找,直到磁盘目录还是找不到,最后报错

5. npm

5.1 npm 网站

npmjs.com

5.2 npm 命令行工具

npm 的第二成含义就是一个命令行工具,只要你安装了node 就已经安装了 npm
npm 也有版本号这个概念
可以通过在命令行中输入
npm --version
升级 npm (自己升级自己)
npm install --global npm

5.3 npm 常用命令

  • npm init ( npm init -y 可以跳过向导,快速生成)
  • npm install (一次性把 dependencies 选项中依赖项全部安装)
  • npm install 包名 (只下载)
  • npm install --save 包名(下载并且保存依赖项(package.json 文件中的 dependencies 选项)
  • npm uninstall 包名 (只删除,如果有依赖项会依然保存) ,简写为 npm un 包名
  • npm uninstall --save 包名 (删除的同时也会把)依赖信息也去除 ,简写 npm un -S 包名
  • npm help (查看使用帮助)
  • npm 命令 --help (查看指定命令的使用帮助)
    例如忘记了 install 命令的简写了,这个时候可以输入 npm uninstall --help 来查看使用帮助

5.4 解决 npm 被墙问题

npm 存储包文件的服务器在国外,有时候会被墙,也就是说速度很慢,所以我们需要解决这个问题。
淘宝镜像:淘宝的开发团队把 npm 在国内做了一个备份。

  • 安装淘宝的cnpm
    # 在任意目录执行都可以
    # --global 表示安装到全局,而非当前目录
    # --global 不能省略,否则不管用
    npm install --global cnpm
    
    接下来你安装包的时候把之前的npm替换成cnpm
    举个栗子:
    # 这里还是走国外的 npm 服务器,速度比较慢
    npm install jquery
    
    # 使用 cnpm 就会通过淘宝的服务器来下载 jquery
    cnpm install jquery
    
  • 如果不想安装 cnpm 又想使用淘宝的服务器来下载,可以使用下面的这个方法
    npm install jquery --registry=https://registry.npm.taobao.org
    
    但是每次这样手动添加参数很麻烦,所以我们可以把这个选项加入配置文件中:
    npm config set registry http://registry.npm.taobao.org
    
    # 查看 npm 配置信息
    npm config list
    
    只要经过了上面命令的配置,则你以后所有的npm install 都会默认通过淘宝的服务器来下载。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值