node.js是什么:
是一个基于Chrome V8引擎的JavaScript环境(ECMAScript+内置模块)
学习方向:
模块系统(核心模块、自定义模块、第三方模块)+ npm
自从es6问世后,使得JavaScript支持了模块话,第三方模块开始逐渐淘汰。
1、安装
打开Node.js 中文网,选择下载选项,选择匹配你当前电脑的系统版本
2、node初体验
使用node跑JavaScript代码
在当前文件加下面有一个node初体验.js文件,
文件内容为:
现在运用node+文件名.js
命令运行该文件
3、node.js运行环境和chrom浏览器运行环境的区别
相同点:
①都是可以运行js代码的容器,更严格一点说:都可以运行ECMAScript
②要下载安装才能使用
不同点:
①各有不同的API: nodejs运行js时,不能写DOM,BOM,也不能用window对象了
②Nodejs 环境可以去实现后端的功能
③浏览器环境可以去实现前端的功能
4、模块系统-核心模块
使用步骤:
引入 const fs=require(fs)
使用
4.1 fs(文件系统模块)
①创建file文件夹实例对象.mkdir()
使用方法:fs.mkdir("路径", 回调函数)
// 1、创建file文件夹
fs.mkdir("./file", function (err) {
if (err) {
return console.log("创建文件夹失败,失败原因为:" + err.message);
}
console.log("文件夹创建成功");
});
②在file文件夹里创建一个new.txt文件实例对象.writeFile()
使用方法:fs.writeFile("路径", "内容",回调函数)
let a = `node.js的初体验`;
const fs = require("fs");
//2、写入文件
fs.writeFile("./file/new.txt", a, function (err) {
if (err) {
return console.log("文件写入失败,错误为:" + err.message);
}
console.log("文件写入成功");
});
*注意:如果该文件已存在,则为覆盖
③查看file文件夹里new.txt文件实例对象.readFile()
使用方法:fs.readFile("路径", "编码格式",回调函数)
// 3、读取文件
fs.readFile("./file/new.txt", "utf-8", function (err, data) {
if (err) {
return console.log("文件读取失败,错误原因为:" + err);
}
console.log(data);
});
4.2 path(路径模块)
引入模块:const path = require('path')
作用:用来处理路径问题:拼接,分析,取后缀名等等。
const path = require('path')
// 拼接html5.jpg的绝对路径
// 1) 找到当前文件夹的绝对路径
console.log(__dirname)
// 2) 加上 html5.jpg
const fs = require('fs')
const path = require('path')
const filePath = path.join(__dirname, 'html5.jpg')
// const filePath = __dirname + '\\html5.jpg'
// 走一步,看一步
console.log(filePath)
fs.readFile(filePath,function(err, data) {
if(err) {
console.log(err)
return
}
console.log(data)
})
扩展:__filename
和__dirname
__filename
:获取当前被执行文件的绝对路径
__dirname
:获取当前被执行文件的文件夹所在的绝对路径
const fs = require("fs");
let a = fs.readFileSync(`${__dirname}/file/new.txt`, "utf-8");
console.log(a);
5、自定义模块
什么是模块化:
一个js文件可以引入其他的js文件,能使用引入的js文件的中的变量、数据,这种特性就称为模块化。
模块化的作用:
使用模块化开发可以很好的解决变量、函数名冲突问题,也能灵活的解决文件依赖问题。
nodejs模块的分类
- 核心模块
-
- 就是nodejs自带的模块,在安装完nodejs之后,就可以随意使用啦。相当于学习js时使用的Array对象。
- 例:fs, http, querystring, path
- 全部模块的源代码 node/lib at master · nodejs/node · GitHub
- 自定义模块
-
- 程序员自己写的模块。就相当于我们在学习js时的自定义函数。
- 第三方模块
-
- 其他程序员写好的模块。nodejs生态提供了一个专门的工具npm来管理第三方模块,后面我们会专门讲到。
- 相当于别人写好的函数或者库。例如我们前面学习的JQuery库,arttemplate等。
自定义模块-基本介绍
目标
掌握自定义模块的使用背景和步骤
背景
我们对代码的封装是以模块(一个独立的.js文件
)为单位进行的。一般的做法是实现好某一个功能之后,封装成一个模块,然后在其它文件中使用这个模块。
类比于js自定义函数,自定义模块的使用场景是:
- 代码需要在项目重用
- 代码需要提供给他人使用
- 代码虽然不需要重用,但封装成模块有利于优化代码结构,方便后期维护与扩展
步骤
一共有两步:
- 定义模块。就是创建一个js文件, 对外导出我们希望导出的内容。
- 使用模块。在需要使用的地方去导入模块文件。
Node.js 中的 CommonJS 的模块化规范
CommonJS 规范
CommonJS 规范中主要规定了以下 3 项内容:
- 导入其它模块时,统一使用 require() 函数。
- 每个 .js 文件,都是一个独立的模块,模块内的成员都是私有的。
- 在每个 JS 模块中,使用 module.exports 向外共享成员。
图示
根目录 ├── user.js # 定义模块 └── test.js # 引入user.js模块
注意
- module.exports 是固定写法,一般放在文件的最末尾,也只用一次。
- module.exports表示当前模块要暴露给其它模块的功能。
-
- 它可以导出对象,数组,函数等等类型。为了方便组织代码,导出对象的情况比较多。
- 不必要导出所有函数,对象,数组等。那些没有导出的部分就相当于这个模块的内部变量了。在下图中变量1,函数1,数组就是模块内部的数据,在外部无法别访问到。
小结
所谓定义模块,就是新建一个js文件。文件取名时,要注意一下:
- 一般会用模块名给它命名。类比于核心模块,例如,你的模块叫myModule,则这个js文件最好叫myModule.js
- 不要与核心模块的名字重复了。就像我们定义变量不要与核心关键字重名,你自己定义的模块也不要叫fs.js,因为nodejs有一个核心模块就叫fs.js。
- 要记得导出模块
自定义模块-实操
假设在工作中我们自己定义了一些工具方法, 而这些工具方法是可以在其他项目中使用的。此时我们就可以采用自定义模块的方式来处理。
素材
以下是一个对时间进行格式化的函数
const formatDate = (dateTime) => { const date = new Date(dateTime) // 转换成Data(); const y = date.getFullYear() let m = date.getMonth() + 1 m = m < 10 ? '0' + m : m let d = date.getDate() d = d < 10 ? ('0' + d) : d return [y,m,d].join('-') }
这个函数如何才能被复用呢?
我们以此为基础,开始做自定义模块的动作
思路
根目录 ├── tool.js # 把我们要用到的公共方法 封装在这个文件中 └── test.js # 测试tool.js中封装的方法
操作
定义模块
// 方法定义在这里
const formatDate = (dateTime) => {
const date = new Date(dateTime) // 转换成Data();
const y = date.getFullYear()
let m = date.getMonth() + 1
m = m < 10 ? '0' + m : m
let d = date.getDate()
d = d < 10 ? ('0' + d) : d
return [y,m,d].join('-')
}
// 通过module.exports来导出模块
module.exports = {
formatDate
};
记得要导出模块: 在文件尾部,使用module.exports来导出模块。
导入模块
完成了模块定义之后,我们就可以在另一个文件中使用这个模块了。
基本步骤是:
1. 导入模块;格式:const 模块名 = require('./模块路径')
2. 先打出来看看;
当一个模块被成功引入之后,就可以类比使用核心模块的过程一样去使用它们了。
下面是示例代码:
// test.js
// 1. 导入模块
// 注意这里使用的是相对路径。可省略.js.
const tool = require('./tool.js');
// 在使用之前请先打印出来看看
console.log(tool);
// 2. 使用模块中的方法
console.log(tool.formatDate(Date.now()))
注意:
- 使用require语句引入你定义好的模块
- 这里必须使用
相对路径
的格式去引入自定义模块。"./" 也不能省略。
练习
将如下的方法补充到上面封装的tool.js中,并导出使用
//tools.js
const relativeTime = (oldTime) => {
const t = new Date(oldTime)
// Date.now():现在的时间戳(毫秒)
// t.getTime():旧时间的时间戳(毫秒)
const diff = Date.now() - t.getTime() // 相隔多少毫秒
// Math.floor 向下取整: 1.7年 ---> 1年前
const year = Math.floor(diff / (1000 * 3600 * 24 * 365))
if (year) {
return `${year}年前`
}
const month = Math.floor(diff / (1000 * 3600 * 24 * 30))
if (month) {
return `${month}月前`
}
const day = Math.floor(diff / (1000 * 3600 * 24))
if (day) {
return `${day}天前`
}
const hour = Math.floor(diff / (1000 * 3600))
if (hour) {
return `${hour}小时前`
}
const minute = Math.floor(diff / (1000 * 60))
if (minute) {
return `${minute}分钟前`
} else {
return '刚刚'
}
}
导出模块的两种方式
目标
了解两种导出的方式(难点,不是重点)
导出模块有两种方式
- exports
- module.exports
// 定义方法,常量
const myPI = 3.14
const add = (a,b) => a + b;
// 导出,两种方法任意都可以
// 方法一:
exports.myPI = myPI
exports.add = add
// 方法二:
module.exports.myPI = myPI
module.exports.add = add
// 方法二(变形)
module.exports = {
myPI,
add
}
在阅读其它人的代码时,可能会遇到这两种不同的写法。所以我们还是有必要了解一下的。
cookie模块,body-parser模块,arry-flatten模块中的导出均采用不同的方式。
两个对象的关系
- 初始exports和module.exports是指向同一块内存区域,其内容都是一个空对象。(exports是module.exports的别名)即:
exports === module.exports // 输出是 true
所以下面两种写法的效果是一样的:
// 写法1 mymodule.js
exports.f = function(){ }
exports.pi = 3.1415926
// 写法2 mymodule.js
module.exports.f = function(){ }
module.exports.pi = 3.1415926
- 在定义模块时:
如果直接给exports对象赋值(例如:exports={a:1,b:2}),此时,exports就不会再指向module.exports,而转而指向这个新对象,此时,exports与module.exports不是同一个对象。
在引入某模块时:以该模块代码中module.exports
指向的内容为准。
图示
结论
在导出模块过程中,建议只用一种方式(建议直接使用module.exports)
*npm见下一章