nodejs笔记

模块化

基本

node的模块化采用CommonJs规范。有一下三个特点:

  • 所有代码运行在模块作用域,不会污染全局作用域
  • 模块可以多次加载,但是只运行一次,之后将会被缓存
  • 模块加载顺序按照其代码中出现的顺序

每个模块(js文件)都有一个内置的module对象,拥有以下属性。

对象属性 描述
id 模块标识符
filename 模块文件名(绝对路径)
loaded 是否已经加载(bool)
parent 调用该模块的模块
children 数组,该模块依赖的其他模块
exports 模块对外输出的值

module.exports

调用方引入模块时,实质获取的是被依赖模块中的module.exports变量。

1
2
3
4
module.exports = {
name : 'xxx',
age : 1
}

module.exports可以导出单值,也可以导出对象。

exports

1
2
//相当于
var exports = module.exports;

每个node脚步里都自带了一个exports变量指向module.exports

1
2
3
4
5
exports.name = 'xx';
exports = { // 将会切断与module.exports的关联
age : 1
}

而且只能通过点语法来添加输出的变量。一般情况下还是选择使用.exports更为稳妥。

require

1
2
var redis = require('redis');
redis.createClient();

使用require即可获取对应模块的module.exports变量。

1
2
3
require('./lib.js');
require('./lib.js').message = "hello";
require('./lib.js').message

第一次加载模块之后,将会缓存模块。

1
2
3
4
5
6
7
// 删除指定模块的缓存
delete require.cache[moduleName];
// 删除所有模块的缓存
Object.keys(require.cache).forEach(function(key) {
delete require.cache[key];
});

可用delete关键字清理缓存模块。

package.json

1
2
$ npm init
$ npm init --yes # 跳过交互式初始化

可用以上两种方式初始化package.json文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"name": "node",
"version": "1.0.0",
"description": "",
"main": "hello.js",
"dependencies": {
"axios": "^0.18.0",
"redis": "^2.8.0"
},
"devDependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
属性 描述
name 项目名称
version 项目版本
description 项目描述
main 项目入口文件,require时就会加载该文件
dependencies 依赖列表
devDependencies 开发版本的依赖列表
scripts 执行脚本命令
keywords 关键字,用于npm搜库时分类
author 作者
license 开源证书

错误处理

uncaughtException处理器

1
2
3
4
5
6
process.on('uncaughtException',function(err){
console.log("Exception!");
console.log(err.message);
});
throw new Error('error');

uncaughtException处理器能够处理进程里未被catch的异常

异步操作的异常

1
2
3
4
5
6
7
try {
setTimeout(function(){
throw new Error('test-error');
},100)
} catch(e){
console.log(e);
}

node无法捕获未来才执行的函数所抛出的异常,异步的异常不能通过不同的try-catch来捕获,需要回调里进行捕获或者注册异常处理器处理。

全局作用域

node的作用域与浏览器(全局和函数)的不同,node的作用域为顶级全局作用域和模块作用域。

node中的this究竟是谁?

1
2
3
4
5
6
7
8
9
10
11
console.log(this === global); // false
console.log(this === module.exports); // true
function foo(){
console.log(this === global); // true
}
foo();
x = 5;
console.log(global.x); // 5
  • 如上,模块内的全局this并非等于真正的顶级作用域global(这个作用域可以跨模块也访问到),模块内的全局this绑定的是module.exports
  • 模块内定义的函数,其this却绑定的是顶级作用域
  • 模块内添加或更改顶级全局(global)变量不应该添加var关键字