node.js学习之旅--node.js全局对象

node.js全局对象主要分为路径变量、控制台、进程对象、定时器的相关方法、Buffer对象、Module对象

Posted by Frewen on October 4, 2018

全局对象API预览

全局对象API

全局:路径变量

  • __filename:展示当前的文件名称,从主目录开始的绝对路径
  • __dirname:展示当前文件所在的文件目录的名称,从主目录开始的绝对路径

任务要求:

  • 在控制台输出 __filename 和 __dirname 两个变量
  • 完成项目目录下,’views’ 子目录中,网页模板 ‘view.html’ 的路径拼接
  • 在控制台输出拼接后的路径信息
#!/usr/bin/node

console.log("filename:",__filename);
console.log("dirname:",__dirname);

/*在文件操作的时候,可以进行目录的拼接,可以用一个文件的绝对路径和相对路径从而得到一个文件
的绝对路径*/

/*method1*/
var file = __dirname + "/view/base.html";// 这种方法并没有考虑不同的操作系统

/*method2*/
var file;
switch(process.platform){
  case "Linux":
    file = __dirname + "/view/base.html";
    break;
  case "win32":
    file = __dirname + "\\view\\base.html";
    break;
  default:
    file = "error";
}

/*method3*/
const path = require("path");
file = path.join(__dirname,"view","base.html");

## 输出结果
filename: /home/wangding/node.js/nodejs-demo/02-global-var/01-file-dir-name.js
dirname: /home/wangding/node.js/nodejs-demo/02-global-var

全局:控制台

控制台输出信息

console控制台:console用于提供控制台标准输出,它是一种调试工具,后来逐渐成为了标准

方法 描述
console.log() 向标准输出流打印字符并以换行符结束
console.info() 向标准输出流打印信息性消息。输出文字外,会显示一个蓝色的惊叹号。
console.warn() 向标准输出流打印警告性消息。输出文字外,会显示一个黄色的惊叹号。
console.error() 向标准输出流打印错误性消息。输出文字外,会显示一个红色的叉子。

任务要求:

  • 定义一个 user 对象,包含三个字段:name, age, qq

  • 使用三种占位符,分别输出三种变量类型:字符串,整数和 JSON 数据

  • 以两种不同占位符的方式输出 user.qq 信息

  • 向标准错误流中输出信息:Error:something wrong!

  • 通过命令行重定向,观察 console.log 和 console.error 两个方法所使用流的区别

    ./01-format.js > output.txt
    ./01-format.js 2> error-msg.txt
    
#!/usr/bin/node

const user = {
  name:"frewen",
  age:21,
  qq:"2622860598"
};

const log = console.log;

//method1
log("name: %s",user.name); // string类型
log("age: %d",user.age); // number类型
log("user: %j",user);// json字符串

//method2
log("qq: " + user.qq);// 字符串拼接 通过+进行连接

//method3
log(`qq: ${user.qq}`);

console.error('Error:something wrong!');
# 输出重定向
在输出控制台中console.log()console.error()没有什么区别,所以可以通过Linux的输出重定向
控制台基准测试
  • 对耗时任务运行的时间进行采样
  • 在控制台输出采样的时间
  • 多运行几次程序,观察同样的耗时任务每次采样的时间是否相同(结果是不同的)
#!/usr/bin/node

function longTask(){
  var n = 0;
  for(var i = 0;i<1000;i++){
    for(var j = 0;j<1000;j++){
      n = n + i*j;
    }
  }
}
console.time("test");// 确定任务开始
longTask();
console.timeEnd("test");// 确定任务结束 两个console的参数必须是一样的
## 输出结果
test91.867ms // 每次测试的结果是不同的

全局:进程

获取平台信息
  • 向控制台打印 CPU 架构信息以及操作系统版本信息
  • 打印进程 id 信息以及 Node.js 可执行文件的绝对路径信息
  • 在脚本中增加标准输入流的读取操作,让程序暂停执行
  • 执行 Linux 命令 ps aux,验证当前进程的 ID 信息和程序中得到的进程 ID 信息相同
  • 打印 Node.js 版本信息,当前登录用户 id 信息,当前登录用户所属组 id 信息以及当前脚本所在路径信息
  • 在命令行执行 ‘node -v’ 命令,验证程序输出的 node.js 版本信息是否正确
  • 在命令行执行 ‘id’ 命令,验证程序输出的登录账户 id 信息是否正确
  • 在命令行执行 ‘pwd’ 命令,验证程序输出的当前工作目录信息是否正确
  • 打印内存使用情况
  • 打印环境变量
  • 在命令行执行 ‘env’ 命令,验证程序输出的环境变量信息正确
#!/usr/bin/node

const log = console.log;

/*向控制台打印 CPU 架构信息以及操作系统版本信息*/
log("arch: ",process.arch);
log("platform: ",process.platform);

## 输出结果
arch:  x64
platform:  linux

/*打印进程 id 信息以及 Node.js 可执行文件的绝对路径信息*/
log("id: ",process.pid);
log("execPath: ",process.execPath);

## 输出结果
id:  2569
execPath:  /usr/bin/node

/*在脚本中让程序暂停执行*/
process.stdin.pause();

/*打印 Node.js 版本信息,当前登录用户 id 信息,当前登录用户所属组 id 信息以及当前脚本
所在路径信息*/

log("version: ",process.version);
log("uid: ",process.getuid());
log("gid: ",process.getgid());
log("pwd: ",process.cwd());

## 输出结果
version:  v6.10.1
uid:  1000
gid:  1000
pwd:  /home/wangding/node.js/nodejs-demo/04-process

/*打印内存使用情况*/
log("rss: ",process.memoryUsage().rss);// 查看系统的常驻内存大小
log("heapTotal: ",process.memoryUsage().heapTotal);//查看 V8 动态分配的总内存大小
log("heapUsed: ",process.memoryUsage().heapUsed);//查看 v8 动态分配的已用内存大小
log("external: ",process.memoryUsage().external);
//查看 v8 管理的绑定到 JS 对象上的 C++ 对象的内存

## 输出结果
rss:  14946304
heapTotal:  7376896
heapUsed:  3498472
external:  8380
/*打印环境变量*/
log("env: ",process.env);
获取命令行参数
  • 获取命令行参数,命令行参数为一个数学表达式
  • 如果没有命令行参数,打印程序的使用说明
  • 如果命令行参数是 –help 或者 -h,打印程序的使用说明
  • 如果命令行参数多于 3 个,多余的参数忽略
  • 对命令行参数的表达式进行求值,打印求值结果
  • 命令行参数的格式如下:
#!/usr/bin/node
// argv 是一个字符串数组 头两个字符串 第一个字符串是node 第二个参数是运行的脚本的绝对路径
/*
console.log(process.argv.length);

for(var i = 0;i<process.argv.length;i++){
  console.log(`${i}:argv - ${process.argv[i]}`);
}
*/

if(process.argv.length === 2 || process.argv[2] == "--help" || process.argv[2] == "-h"){
  console.log("usage: cmd-name [OPTION] [expression]\nevaluate the expression.\n\nMandatory arguments to long options are mandatory for short options too.\n-h, --help output help information and exit"
      )} else{
  console.log(process.argv[2] + "=" + eval(process.argv[2]));        
}

# 输出格式
./02-calc.js
usage: cmd-name [OPTION] [expression]
evaluate the expression.

Mandatory arguments to long options are mandatory for short options too.
-h, --help output help information and exit

./02-calc.js 2+4
2+4=6

./02-calc.js 2\*Math.PI
2*Math.PI=6.283185307179586
处理退出码

退出码实质上是给程序看的,在Linux程序中,有时候子进程会输出退出码,父进程通过查看子进程输出的退出码来判断是否正确

  • 通过命令行参数获取程序的退出码,以该退出码退出程序
  • 通过 echo 命令查看程序的退出码
  • 对命令行参数的退出码,做数据合法性校验
#!/usr/bin/node

var code = process.argv[2];
if(typeof code === 'number'){
  console.log("命令行参数类型不符合!");
  process.exit(1);
}
if(process.argv.length <3){
  console.error("请给出命令行参数!");
  process.exit(1);
}
process.exit(code);

// process.exit(code:number) ?表示可以有也可以表示没有
// 获取退出码 echo $?
操作标准输入输出流
  • 逐条打印提示信息:姓名、邮箱、QQ、手机
  • 读取用户键盘输入信息,保存到对象中
  • 用户键盘输入结束后,打印完整的对象信息
#!/usr/bin/node

const msg = ['name','email','qq','mobile'];

var i = 0,
  me = {};
console.log(msg[i] + ':');
process.stdin.on('data',(data)=>{
  me[msg[i]] = data.slice(0,data.length-1).toString('utf-8');// slice 是将回车进行去掉
  i++;
  if(i == msg.length){
    console.log(me);
    process.exit();
  }
  console.log(msg[i] + ':');
});
process.stdin.on('end',()=>{
  console.log(me);
});
处理信号量
  • 接收信号量,并对信号(SIGINT 和 SIGTSTP)进行处理
  • 用控制台快捷键,给程序脚本发送信号量,测试程序的功能逻辑
  • CTRL+C 发送 SIGINT 信号量,让程序退出
  • CTRL+Z 发送 SIGTSTP 信号量,让程序挂起
  • 用 kill 命令,给程序脚本发送信号量,测试程序的功能逻辑
#!/usr/bin/node

process.stdin.resume();

process.on('SIGINT',()=>{
  console.log('you have pressed Ctrl+C');
  process.exit();
})

process.on('SIGTSTP',()=>{
  console.log('you have pressed Ctrl+Z');
})
// 杀掉程序的两种方式
/*
第一种: 通过 Ctrl+C 和 Ctrl+Z
第二种: 通过kill -2 pid 和 kill -20 pid
*/
实现 my-kill 程序
  • 获取命令行参数,得到进程 ID 信息和信号量标识符
  • 向指定进程 ID 的进程发送特定的信号量
  • 用 05-my-kill.js 脚本,向 05-signal.js 脚本发送信号量,测试两个程序的功能逻辑
#!/usr/bin/node

const pid = process.argv[2];
const sig = process.argv[3];

process.kill(pid,sig);

全局:定时器

实现延迟执行任务
  • 定义一个定时炸弹对象
  • 定时炸弹对象和 setTimeout 函数绑定
  • 定时炸弹爆炸
  • 在定时炸弹爆炸之前,拆除定时炸弹
 #!/usr/bin/node

/*console.log('first');

global.setTimeout(function(){
  console.log('second');
},2000);

//说明JavaScript的异步执行

console.log('third');*/

function Bomb(){
  this.message = 'Bomb';
}

Bomb.prototype.explode = function(){
  console.log(this.message);
}

var b = new Bomb();

// 此时直接执行时,this指向的是timeout对象
var time = global.setTimeout(b.explode.bind(b),2000);

//global.clearTimeout(time);
实现定时执行任务
  • 定时执行任务
  • 用两种方式取消定时器,分别是:
    • 设置定时器运行时间总时长,时间到后取消定时器;
    • 设置计数器,重复执行任务次数达到上限,取消定时器;
#!/usr/bin/node

console.log("start");

const time = global.setInterval(loop,500);

function loop(){
  // count ++;
  console.log('I will loop forever');
  if(count === 6){
  		clearInterval(time);
	}
}
// method1
global.setTimeout(function(){
  global.clearInterval(time);
  console.log('end');
},3000);
// method2
var count = 0;

Node.js Buffer(缓冲区)

JavaScript 语言自身只有字符串数据类型,没有二进制数据类型。

但在处理像TCP流或文件流时,必须使用到二进制数据。因此在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门存放二进制数据的缓存区。

在 Node.js 中,Buffer 类是随 Node 内核一起发布的核心库。Buffer 库为 Node.js 带来了一种存储原始数据的方法,可以让 Node.js 处理二进制数据,每当需要在 Node.js 中处理I/O操作中移动的数据时,就有可能使用 Buffer 库。原始数据存储在 Buffer 类的实例中。一个 Buffer 类似于一个整数数组,但它对应于 V8 堆内存之外的一块原始内存。

Buffer基本操作
  • 实例化一个 buffer 对象 buf1,缓冲区的大小是 256 字节,初始化第一个字节为23,控制台打印 buf1 的长度和内容
  • 通过循环初始化 buf1 的每个字节,每个字节比上个字节大 1,控制台打印 buf1 的内容
  • 对 buf1 做切片操作,取出后 10 个字节,存放到 buf2 中,控制台打印 buf2 的内容和长度
  • 对 buf2 做填充操作,所有字节填充为零,控制台打印 buf2 的内容
  • 用数组(数组内容随意)初始化 buf3,控制台打印 buf3 中的内容和长度
  • 用字符串(字符串内容随意)初始化 buf4,控制台打印 buf4 中的内容和长度,打印 buf4 字符串
  • 将 buf4 的内容复制到 buf3 中,打印复制后的 buf3 内容和长度,打印 buf3 字符串
#!/usr/bin/node
// 初始化对象 new Buffer()
const log = console.log;
var buf1 = new Buffer(256);
buf1[0] = 23;
log('buf1 length:',buf1.length);
log('buf2 content:',buf1);

// 循环初始化
for(var i = 0;i<buf1.length;i++) buf1[i] = i;
log('buf1 new content:',buf1);

// 切片填充操作
var buf2 = buf1.slice(246,257);
log('buf2 length:',buf2.length);
log('buf2 new content:',buf2);
buf2.fill(0);
log('buf2 fill content:',buf2);

// 数组进行初始化
var arr = ['a',0xBA,0xDF,0x00,0x00,255,10];
var buf3 = new Buffer(arr,'utf-8');
log('buf3 length:',buf3.length);
log('buf3 content:',buf3);

// 字符串初始化
var buf4 = new Buffer('Hello World','utf-8');
log('buf4 length:',buf4.length);
log('buf4 content:',buf4);
log('buf4 string content:',buf4.toString('utf-8'));

// 复制内容
buf3.copy(buf4);
log('buf3 length:',buf3.length);
log('buf3 content:',buf3);
/*
buf.copy(targetBuffer[, targetStart[, sourceStart[, sourceEnd]]])
参数描述如下:
targetBuffer - 要拷贝的 Buffer 对象。
targetStart - 数字, 可选, 默认: 0
sourceStart - 数字, 可选, 默认: 0
sourceEnd - 数字, 可选, 默认: buffer.length
*/
Buffer 编码

在计算机中,文件的编码有两种方式,一种方式是通过文本文件进行编码(例如:utf-8 ascii utf16le),另一种方式是通过二进制文件进行编码的(例如:base64 lantin1 hex

Buffer编码

其中对于base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息。采用Base64编码具有不可读性,需要解码后才能阅读。

HTTP对于用户名和密码的校验主要通过两种方式

  • 基本校验:用户名和密码之间通过冒号 进行分隔,之后通过base64编码形成加密文件,上传至服务器,服务器通过解密进行解密
  • 摘要校验:通过MD5码进行校验

任务要求:

  • 从命令行参数获取登录网站的用户名和密码信息
  • 命令行参数的格式:cmd user_name password
  • 命令行参数不正确时,提示用户命令行参数的正确格式
  • 在控制台打印用户名和密码信息
  • 将用户名和密码信息拼接成一个字符串,用冒号(:)分割
  • 将拼接后的字符串转化成 base64 编码,并打印在控制台上
#!/usr/bin/node
if(process.argv.length !== 4){
  console.log('请输入正确的参数个数');
  process.exit(-1);
}
const name = process.argv[2],
      pwd = process.argv[3];
if(name == '' || pwd == ''){
  console.log('请输入正确的参数!');
  process.exit(-1);
}
var str = name + ':' + pwd;
var buf = new Buffer(str);
console.log("base64 content:",buf.toString('base64'));
Buffer 解码
  • 从命令行参数获取用户名和密码信息的 base64 编码字符串
  • 命令行参数的格式:cmd base64_string
  • 命令行参数不正确时,提示用户命令行参数的正确格式
  • 将 base64 编码的字符串转换成 utf8 编码的字符串
  • 将还原后的用户名和密码信息打印在控制台上
  • 还原信息不正确时,请提示错误信息
#!/usr/bin/node

if(process.argv.length !== 3 || process.argv[2] == ''){
  console.log('请按照命令行参数的格式:cmd base64_string输入合法的参数');
  process.exit(-1);
}
const str = process.argv[2];
var buf = new Buffer(str,'base64');// 后面的编码格式不能缺少
var namepwd = buf.toString('utf-8');
var data = namepwd.split(':');
if(data.length !== 2){
  console.error('信息有误!');
  process.exit(-1);
}
console.log("name:" + data[0] + ' pwd:' + data[1]);
Buffer 实现 Data URI

DATA-URI 是指可以在Web 页面中包含图片但无需任何额外的HTTP 请求的一类URI.(类似将图片的base64码添加到src属性上)

Data URL格式

  • 从命令行参数获取图片文件名
  • 命令行参数的格式:cmd file_name
  • 命令行参数不正确时,提示用户命令行参数的正确格式
  • 命令行参数的图片文件不存在时,提示错误信息
  • 把图片数据生成 data URI 格式的数据
  • 把 data URI 数据打印到控制台
  • 把 data URI 数据嵌入到 HTML 页面中
  • 创建一个 HTTP 服务,监听 8080 端口
  • 浏览器请求 HTTP 服务的 URL 地址时,得到嵌入图片数据的 HTML 页面

任务提示:

> 文件操作需要导入 fs 模块: const fs = require('fs');
> 读取文件数据可以使用 readFileSync 方法:var data = fs.readFileSync(fileName);
> 同步读取文件时,如果文件不存在会抛出异常,可以使用 try-catch 捕获异常
> 获取文件扩展名,需要导入 path 模块:const path = require('path');
> 获取文件扩展名使用 path 模块的 extName 方法:var ext = path.extname(fileName);
const http = require('http'),
      fs = require('fs'),
      path = require('path');
var filename = process.argv[2];
if(process.argv.length !== 3) {
  console.error('命令行参数格式:cmd fileName');
  process.exit(-1);
}
try {
  var data = fs.readFileSync(filename).toString('base64');
} catch(e) {
  console.error(e.message);
  process.exit(-1);
}
var ext = path.extname(filename);
var datauri = 'data:img/' + ext.slice(1,ext.length) + ';base64,' + data;
html = '<!DOCTYPE html><html><head><title>img</title></head><body><img src="' + datauri + '"/></body></html>';
http.createServer((req,res)=>{
  	res.end(html);
}).listen(8080);
Buffer 读取位图信息

读取一个BMP文件,需要知道二进制文件的存储的三方面内容:

  • 位置:也就是对应的偏移量(相较于第一个位置的偏移量) offset
  • 大小:4byte 8byte
  • 含义:这一个字段代表是什么含义

BMP格式

下列显示的所对应的offset以及size:

offset and size

任务要求:

  • 从命令行参数获取图片文件名
  • 命令行参数的格式:cmd file_name
  • 命令行参数不正确时,提示用户命令行参数的正确格式(length)
  • 命令行参数的图片文件不存在时,提示错误信息(try catch)
  • 获取图片的宽度、高度和颜色深度三个信息,并打印在控制台上
#!/usr/bin/node

const filename = process.argv[2],
      fs = require('fs'),
      buf = fs.readFileSync(filename),
      log = console.log;
log('BMP width:',buf.readUInt32LE(18));
log('BMP Height:',buf.readUInt32LE(22));
log('color deapth:',buf.readUInt16LE(28));
/*
buf.readUInt32LE(offset[, noAssert])
根据指定的偏移量,使用指定的 endian 字节序格式读取一个无符号 32 位整数,小端对齐。 若参数 noAssert 为 true 将不会验证 offset 偏移量参数。 这意味着 offset 可能会超出buffer 的末尾。默认是 false。
*/
Buffer 写入位图文件
  • 从命令行参数获取图片文件名
  • 命令行参数的格式:cmd file_name
  • 命令行参数不正确时,提示用户命令行参数的正确格式
  • 写一个 16 * 16 像素,颜色深度为 32 位的位图文件
  • 位图的所有像素为红色
#!/usr/bin/node

const fs = require('fs');

const width = 16,
      height = 16;

var pixelByteSize = width * height * 4;
var totalSize = pixelByteSize + 54;

var buf = new Buffer(totalSize);

buf.fill(0);

// head
buf.write('BM');
buf.writeUInt32LE(totalSize, 0x02);
buf.writeUInt32LE(54, 0x0a);
buf.writeUInt32LE(40, 0x0e);
buf.writeUInt16LE(1, 0x1a);
buf.writeUInt16LE(32, 0x1c);
buf.writeUInt32LE(pixelByteSize, 0x22);
buf.writeInt32LE(width, 0x12);
buf.writeInt32LE(height, 0x16);

// data
for(var i=54; i<totalSize; i+=4) {
   buf.writeUInt32LE(0xff0000ff, i);
}

fs.writeFile('./out.bmp', buf, (err) => {
    if(err != null) {
      console.error(err);
      process.exit(1);
    }
});

全局:模块管理

Node应用是由模块组成的,Node遵循了CommonJS的模块规范,来隔离每个模块的作用域,使每个模块在它自身的命名空间中执行。

JS 模块化的两种方案分别是:AMDCommonJS

  • AMD 规范的主要内容:AMD是异步模块加载机制。从它的规范描述页面看,AMD很短也很简单,但它却完整描述了模块的定义,依赖关系,引用关系以及加载机制。define和require这两个定义模块、调用模块的方法,合称为AMD模式

  • CommonJS规范的主要内容:模块必须通过 module.exports 导出对外的变量或接口,通过 require() 来导入其他模块的输出到当前模块作用域中。

module分类

使用第三方模块
  • 导入 date-now 模块
  • 调用 date-now 模块的 now 方法,在控制台打印 now 的运行结果
  • 安装 date-now 模块,运行程序
  • 创建 package.json 文件,用 npm install module-name -S 安装模块
  • 查看 package.json 文件中的依赖项
#!/usr/bin/node

var now = require('date-now');

console.log(now());
console.log(Date.now());

## 输出结果
1537882086300
1537882086304

在程序运行的时候,程序会报错,因为对于该程序,没有date-now这个模块,因此,需要先通过npm包管理器进行安装

#npm缩写于 Node Packaged Modules, 是 node.js 的模块管理器
~/node.js/nodejs-demo/07-module(master) » npm install date-now

关于在每一个包管理器中的package.json文件,这个文件是一个项目配置文件,里面有项目配置的一些信息,同时该文件还包括所需要的模块依赖项

使用 package.json 配置文件管理第三方模块的过程:

  • 首先我们创建一个文件夹package,在这个文件夹里面初识一个package.json文件
~/package » npm init
# 此时我们打开package.json文件
~/package » cat package.json                            wangding@OFFICE
{
  "name": "package",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "date-now": "^1.0.1"
  }
}

其中需要注意"devDependencies""dependencies" ,其中前者是开发时以来的npm模块,后者是自己所写的打包成的应用程序所需要的npm模块

  • 安装第三方模块:npm install moduleName -S(--save) ,此时该模块会自动添加到package.json文件里的"dependencies" 里面
  • 发布程序和 package.json 配置文件(发布到npm网站上),然后使用时:运行 npm install 安装第三方模块就可以使用自己的创建的第三方模块了

如果我们使用的是别人的npm的包管理器的时候,只需要在别人的项目下运行npm install命令,就可以让程序自动下载程序运行时所需要的所有模块

创建并使用模块,导出变量
  • 在 02-export-var.js 脚本中导出变量 Math.PI打印 module 信息
  • 在 02-main.js 脚本中导入上面的模块
  • 测试模块的接口,观察 module 中的 exports 信息
#!/usr/bin/node
// export-var.js
module.exports = Math.PI;

console.dir(module);// dir是输出一个对象
#!/usr/bin/node

var PI = require('./02-export-var');

console.log('\n'+ PI);
console.log();
console.dir(module);
创建并使用模块,导出函数
  • 在 02-export-function.js 脚本中定义 circle 函数
  • 函数的入口参数是圆的半径
  • circle 函数返回一个对象
  • 对象中有两个成员函数,分别计算:圆的面积和周长
  • 导出 circle 函数
  • 在 02-main.js 脚本中导入上面的模块
  • 测试模块的接口,观察 module 中的 exports 信息
#!/usr/bin/node
// 02-export-function.js
function circle(radius){
  return {
    diameter:function(){return 2*radius;},
    circumference:function(){return 2*Math.PI*radius;},
    area:function(){return Math.PI*radius*radius;}
  };
}

module.exports = circle;
var circle = require('./02-export-function');

const log = console.log;

log(circle(20).diameter());
log(circle(20).circumference());
log(circle(20).area());
创建并使用模块,导出对象
  • 在 02-export-object.js 脚本中定义 Circle 对象字面量
  • Circle 对象有三个公开方法,分别计算圆的直径、面积和周长
  • 导出 Circle 对象,打印 module 信息
  • 在 02-main.js 脚本中导入上面的模块
  • 测试模块的接口,观察 module 中的 exports 信息
#!/usr/bin/node
// 02-export-object.js 
module.exports = {
  diameter: function(radius){return 2*radius;},
  circumference:function(radius){return 2*Math.PI*radius;},
  area:function(radius){return Math.PI*radius*radius;}
}
var circle = require('./02-export-object');

const log = console.log;

log(circle.diameter(20));
log(circle.circumference(20));
log(circle.area(20));
使用全局对象 global
  • 在 03-global.js 定义模块级变量 pi, 函数 circle 以及对象字面量 objCircle
  • 编写 03-main.js 脚本,导入 03-global.js 脚本
  • 使用 03-global.js 脚本中的变量、函数和对象
  • 运行 03-main.js,观察程序结果,理解程序出错的原因
  • 修改 03-global.js 脚本,将变量、函数和对象定义为全局的
  • 运行 03-main.js 脚本,观察程序结果,理解程序工作原因
#!/usr/bin/node
// 03-global.js
global.pi = Math.PI;

global.circle = (radius)=>{
  return {
    circumference:function(){return 2*Math.PI*radius;},
    area:function(){return Math.PI*radius*radius;}
  }
}

global.circleobj = {
  circumference:function(radius){return 2*Math.PI.radius},
  area:function(radius){return Math.PI*radius*radius}
}
#!/usr/bin/node
// 03-main.js
require('./03-global.js');
console.log(global.pi);
console.log(global.circle(20).circumference());
console.log(global.circleobj.area(20));
使用模块级变量在对象间共享信息
  • 编写 04-share.js 脚本,定义模块级变量 count,定义构造函数 Num
  • Num 有两个公开方法:add 让 count 加一,getCount 得到 count 的值
  • 导出构造函数 Num
  • 编写 04-main.js 脚本,导入 Num 构造函数
  • 用 Num 实例化 n1 和 n2 两个对象
  • n1.add() 方法调用两次,控制台打印 n1.getCount() 和 n2.getCount()
  • n2.add() 方法调用一次,控制台打印 n1.getCount() 和 n2.getCount()
  • 运行 04-main.js 程序,观察程序运行结果,理解程序工作原理
#!/usr/bin/node
// 04-share.js
var count = 0;
function Num(){
  this.add = ()=>{count++;}
  this.getcount = ()=>{console.log(count);};
}

module.exports = Num;
#!/usr/bin/node
// 04-main.js
var Num = require('./04-share.js');
var n1 = new Num();
var n2 = new Num();

n1.add();
n1.add();
n1.getcount();
n2.getcount();
n2.add();
n1.getcount();
n2.getcount();
## 输出结果
2
2
3
3
npm模块的目录结构和程序结构

目录结构 程序结构