Node | 入门知识梳理Node.js入门知识梳理。Node.js 是 JavaScript 运行环境,使得 JS
1 Node 总起
1.1 Node.js是什么
- Node.js 是 JavaScript 运行环境,使得 JS 可以运行在浏览器以外的地方
- 单线程,通过异步的方式来处理并发的问题
- 「浏览器中的 JS VS Node.js 中的 JS」
- 基本语法一致,ECMAScript
- Node 没有 Bom、Dom
- Node 环境为 JavaScript 提供了一些服务器级别的API
- 文件的读写
- 网络通信、http服务
- 构建于 Chrome 的 V8 引擎之上
- 引擎:用于解析和执行 JS 代码,V8 是目前公认最快引擎
- Node 作者把 V8 引擎移植出来,开发了一个独立的 JavaScript 运行时环境
- node 特性
Node.js uses an event-driven,non-blocking I/O mode that makes it lightweight and efficent.
Node.js package ecosystem,npm,is the larget scosystem of open sourcr libraries in the world
- 事件驱动、非阻塞I/O模型(异步)、轻量和高效
- npm:最大的开源生态系统,存放绝大多数 JS 相关的包
- Node能做什么
- Web服务器后台
- 命令行工具 :npm下载包,
npm install jquery
1.2 Node 运行 JS
安装:
- 建议安装到默认位置,并勾选“自动安装必要工具”
node -v
,出现版本号,即表示安装成功
运行:
- 打开终端,定位脚本文件的所属目录
- 输入
node 文件名
执行对应的文件 - 注意:文件名不要用
node.js
来命名,也最好不要使用中文和空格
1.3 npm start
- 如下代码定义了一个
start
脚本,运行npm start
时会调用它来启动服务器。npm start
实际上运行了node ./bin/www
- 文件
/bin/www
是应用入口。它做的第一件事是 require 真实的应用入口(项目根目录中的app.js
) npm run devstart
运行nodemon ./bin/www
"scripts": {
"start": "node ./bin/www",
"devstart": "nodemon ./bin/www"
},
2 核心模块
2.1 文件读写模块
fs(file-system)
核心模块,提供了所有文件操作相关的API
(1)文件读取
// 1.引入fs核心模块
var fs = require('fs');
// 2.读取文件
fs.readFile('./data/a.txt',function(err,data){
if(err){
console.log('文件读取失败');
}
else{
console.log(data.toString());
}
})
(2)文件写入
// 1.引入fs核心模块
var fs = require('fs');
// 2.将数据写入文件
fs.writeFile('./data/a.txt','我是文件写入的信息',function(err,data){
if(err){
console.log('文件写入失败');
}
else{
console.log(data.toString());
}
})
2.2 http 服务器
// 1.加载http核心模块
var http = require('http');
// 2.使用http.createServer()创建一个web服务器
var server = http.createServer();
// 3.服务器接收请求、处理请求、发送响应
//当客户端请求过来,就会自动触发服务器的request请求事件,然后执行回调处理函数
server.on('request',function(){
console.log('收到客户的请求了')
})
// 4.绑定端口号,启动服务
server.listen(3000,function(){
console.log('runing...')
})
2.3 path 操作模块
path.basename
:获取路径的文件名,默认包含扩展名path.dirname
:获取路径中的目录部分path.extname
:获取路径中的扩展名部分path.parse
:把路径转换为对象path.join
:拼接路径path.isAbsolute
:判断一个路径是否为绝对路径
3 模块化
(1)模块化编程:
- 不同功能的代码分离到不同的模块中
- 一个干净的主文件(index.js)+ 好维护可复用的干净的模块
(2)通过 script 标签实现的模块化
- 没办法按需引入
- 模块间的相互依赖关系往往非常复杂,必须要按顺序引入
3.1 node 中的模块
- 核心模块
fs
文件操作http
http服务操作模块url
路径操作模块path
路径处理模块os
操作系统信息
- 第三方模块: 通过npm下载
- 自定义模块 : 自己创建的 js 文件
3.2 CommonJs
CommonJs 是 Node.js 中默认使用的模块化标准。
- 模块就是一个js文件,拥有模块作用域,模块内部变量是私有的,外部无法访问。避免变量命名冲突污染的问题
- CommonJS模块内部定义了一个
module
对象,其存储了当前模块的基本信息 - module对象用
exports
属性 指定需要向外部暴露的内容 - 其他模块通过
require
来获取这些暴露的内容
「 Node.js会将以下内容视为CommonJS模块 」
.cjs
文件- 默认情况下的
.js
文件(未设置package.json
的type
属性)
3.2.1 加载require
(1) 核心模块
核心模块本质也是 JS 文件,通过暴露了一个对象来提供一些方法
核心模块文件已经被编译到了 node 的可执行程序文件中,只需要按照名字加载
(2) 第三方模块: 先通过 npm 下载,然后require('包名')
来加载
// 1.加载核心模块
let fs = require('fs');
// 2. 加载第三方模块
var template = require('art-template');
//3. 加载自定义模块
var zxx = require('./zxx.js')
//{foo:...,add:...}//export的对象
//按需引入
var zxx = require('./zxx.js').foo
var {foo} = require('./zxx.js')
(3)自定义模块
加载.js
文件模块时,模块路径必须以/
、./
或../
开头。否则 node 认为你要加载的是核心模块或node_modules
中的第三方模块。
加载文件夹模块时,和加载第三方模块的方式类似,文件夹中必须有一个模块的主文件。如果文件夹中含有package.json文件且设置了 main属性,则main属性指定的文件会成为主文件,导入模块时就是导入该文件。如果没有package.json,则node会按照index.js、index.node的顺序寻找主文件。
3.2.2 导出export
对于希望可以被其他模块访问到的成员,需要把它挂载到 exports 接口对象中
(1)module.exports 和 exports
① module.exports
每个模块中都有一个 module 对象,module 对象中有一个 exports 对象。我们可以把需要导出的成员都挂载到module.exports
接口对象中:module.exports.xxx = xxx
② exports
Node为了简化代码,就在每一个模块中都提供了一个成员 exports
,它是对 module.exports
的引用,初始时它指向 module.exports
。所以可以用exports.xxx = xxx
取代module.exports.xxx = xxx
如果直接给 exports
赋值,它将不再指向 module.exports
,因此不会导出任何内容
(2)导出单个内容
- 给
module.exports
赋值。单个对象、函数、类等都可作为导出内容 - 给
exports
添加属性。exports.key = value
(3)导出多个内容
module.exports
适用导出单内容。可以将多个内容封装在一个对象中,然后将整个对象赋值给它。exports
适用于导出多个内容。直接在 exports 上添加多个属性,每个属性都代表一个导出项。- 当模块需要导出单个对象的时候必须使用
module.exports = {xxx}
的方式,使用exports = {xxx}
会修改其引用,使其不再指向module.exports
,导致无法导出(因为每个模块最终return的是module.exports
而非exports
)
//导出单个/多个内容--exports
exports.a = 123;
exports.d = 'hello';
exports.b = function(){
console.log('bbb')
};
exports.c = {
foo:"bar"
};
//导出单个内容--module.export
module.exports = 'hello';
//后者会覆盖前者
module.exports = function add(x,y) {
return x+y;
}
//导出多个成员----module.export
module.exports = {
foo:'hello',
add:function() {
return x+y;
}
};
// 错误示例:修改了 exports 的引用
exports = { key: value };
3.3 模块的包装
每一个 CommonJS 模块在执行时,外层都会被套上一个函数
在模块里console.log(arguments)
就能查看到
(function(exports, require, module, __filename, __dirname) {
// 模块里的代码会被放到这里
});
我们使用的 exports、require,实际上以参数的形式传递进模块的。
exports
:设置模块向外部暴露的内容;require
引入模块的方法module
:当前模块的引用__dirname
:动态获取当前模块文件所属目录的绝对路径__filename
:动态获取当前文件的绝对路径(包含文件名)
例如,当前模块文件位于 /projects/src/index.js, __dirname 返回 /projects/src,__filename 返回 /projects/src/index.js
3.3.1__dirname
和__filename
- 不受 node 命令所属路径影响
- 全局变量,可以在任何模块中直接使用,无需额外引入
- 模块中的路径标识(
require(...)
)相对于当前文件模块,不受node命令所处路径影响 - 而文件操作路径(如读取/写入文件等)默认是相对于 Node.js 命令所处的路径。因此,文件操作中使用相对路径是不安全的,建议统一用以上两个成员
var fs = require('fs');
var path = require('path');
// console.log(__dirname + 'a.txt');
// path.join方法会将文件操作中的相对路径都统一的转为动态的绝对路径
fs.readFile(
path.join(__dirname + '/a.txt'),
'utf8',
function(err,data){
if(err){ throw err }
console.log(data);
});
3.4 ES6 模块化
ES6 模块化用import()
方法
「 Node.js 默认用的是 CommonJs,想要使用 ES 模块化 」
- 方式一,直接将所有的 js 文件修改为 mjs 扩展名
- 方式二,修改 package.json 中 type 属性为 module(默认是 commonjs)
【注意】
- ES 模块的官方标准不能省略拓展名
- ES 模块导入的内容都是常量,不能随便赋值
- 一个模块只有一个默认导出,默认导出的只能是一个值(对象/函数/类/数值...),不能是语句
- 引入默认导出不需要
{}
;可以随意取名。 - 尽量避免全部导入,影响打包性能使得项目臃肿,推荐按需导入
- ES 模块都是运行在严格模式下的
- ES 模块化在浏览器中也可以使用,但是一般不直接用,而是结合打包工具用
// 导出变量(命名导出)
export let name1, name2, …, nameN;
export let name1 = 123, name2 = {}, …, nameN;
// 导出函数(命名导出)
export function functionName(){...}
// 导出类(命名导出)
export class ClassName {...}
// 导出一组值
export { name1, name2, …, nameN };
// 重命名导出
export { variable1 as name1, variable2 as name2, …, nameN };
// 解构赋值后导出
export const { name1, name2: bar } = obj;
//默认导出
export default name1;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };
export let name1 = 20; //错误
let name1;
export name1 = 20; //对
// 聚合模块
export * from …; // 将其他模块中的全部内容导出(除了default)
export * as name1 from …; // ES2O20 将其他模块中的全部内容以指定别名导出
export { name1, name2, …, nameN } from …; // 将其他模块中的指定内容导出
export { import1 as name1, import2 as name2, …, nameN } from …; // 将其他模块中的指定内容重命名导出
export { default, … } from …;
// 引入默认导出,不需要{},可以随意取名
import hahaha from "module-name";
// 将所有模块导入到一个对象中,并将该对象命名为name
import * as name from "module-name";
// 按需引入模块中的指定内容,{}里的名字要和导出处的名字一致
import { name1 } from "module-name";
import { name1 , name2 } from "module-name";
// 以指定别名引入模块中的指定内容
import { name1 as alias1 } from "module-name";
import { name1 , name2 as alias2 , [...] } from "module-name";
// 引入默认和其他内容
import defaultExport, { name1 [ , [...] ] } from "module-name";
import defaultExport, * as name from "module-name";
// 引入模块---执行了一遍模块里的代码但是没有拿到export的东西
import "module-name";
4 npm 包管理器
npm是一个命令行工具,是node包管理器,安装了node就默认安装了npm。
4.1 常用命令
npm --version
查看npm的版本
npm install --global npm
升级npm
npm init
生成package.json说明书文件
npm init --yes (npm init -y)
可以跳过向导,快速生成
npm install (npm i)
一次性把dependencies选项中的依赖项全部安装
npm install 包名
npm install 包名1 包名2
仅下载
npm i 包名@版本号
下载指定版本
npm install lodash@"> 3.2.0"
npm install --save 包名
下载并且保存依赖项(package.json文件中的dependencies选项)
npm update 包名
升级模块
npm uninstall 包名 (npm un 包名)
只删除,依赖项会依然保存
npm uninstall --save 包名
删除的同时也会把依赖信息全部删除
(注意:npm5 之后不需要--save,它会自动保存依赖信息)
--no-save
不要保存依赖
npm install lodash -D/-save-dev
保存到开发依赖
npm help
查看使用帮助
npm 命令 --help
看具体命令的使用帮助(npm uninstall --help)
npm list
以树型结构列出当前项目安装和依赖的模块
npm list -global
列出全局安装的模块npm list 包名
列出单个模块
npm view/V/info/show 包名
查看包信息
安装完的打印信息
added 1 package 表示安装了一个包,audited 2 packages表示检查了两个包的安全漏洞,found 0 vulnerabilities表示发现了0个漏洞,简单说,安装成功了
4.2 国内镜像
npm 存储包文件的服务器在国外,下载速度很慢。 淘宝的开发团队在国内做了一个镜像:
使用淘宝的cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org;
# 安装 cnpm 并指定淘宝镜像作为源
# --global表示安装到全局,可简写为-g
# 安装到全局就可以在任意目录执行cnpm命令
# 走国外的npm服务器下载jQuery包,速度比较慢
npm install jQuery;
# 使用cnpm就会通过淘宝的服务器来下载jQuery
cnpm install jQuery;
# 不想安装cnpm又想使用淘宝的服务器来下载
npm install jquery --registry=https://npm.taobao.org;
# 每次手动加参数很麻烦,可以把这个选项加入到配置文件中
npm config set registry https://npm.taobao.org;
# 查看npm配置信息
npm config list;
# 查看 registry 是否配置正确
npm config get registry
# 配置后所有的npm install都会通过淘宝的服务器来下载
# 恢复原版配置
npm config delete registry
4.3 Yarn 和 Pnpm
早期的npm存在有诸多问题,yarn 和 pnpm 的出现就是为了帮助我们解决.
corepack enable #启用corepack
yarn -v #查看yarn版本
corepack prepare yarn@stable --activate #切换yarn版本到最新
corepack prepare yarn@1 --activate #切换到1.X.X
yarn init (初始化,创建package.json)
yarn add xxx(添加依赖)
yarn add xxx -D(添加开发依赖)
yarn remove xxx(移除包)
yarn(自动安装依赖)
yarn run(执行自定义脚本)
yarn <指令>(执行自定义脚本)
yarn global add(全局安装)
yarn global remove(全局移除)
yarn global bin(全局安装目录)
npm install -g pnpm
pnpm init(初始化项目,添加package.json)
pnpm add xxx(添加依赖)
pnpm add -D xxx(添加开发依赖)
pnpm add -g xxx(添加全局包)
pnpm install(安装依赖)
pnpm remove xxx(移除包)
pnpm config set registry https://registry.npmmirror.com
pnpm config delete registry
4.4 package.json
package.json
每一个项目的根目录下都要有一个package.json
文件
- 用于描述项目的元数据和依赖项信息的文件,包含项目的名称/版本/作者/许可证等元数据信息。
- 本质是JSON对象,每个属性就是当前项目的一项设置
- 其中的
dependencies
选项包含了项目运行所依赖的第三方包的列表及版本范围;devDependencies
指定项目开发所需要的模块 - package.json 还可以定义一些脚本命令,用于执行各种开发任务,如构建、测试和部署等
- 这个文件可以通过
npm init
自动初始化出来 - 如果不小心删掉了
node_modules
,只需执行npm install
就会自动把package.json
中的dependencies
中所有的依赖项全部都下载回来
package.json
示例
{
"name": "Hello World", #项目名
"version": "0.0.1", #项目版本
"author": "张三",
"description": "第一个node.js程序",
"keywords":["node.js","javascript"],
"repository": { #仓库地址
"type": "git"
"url": "https://path/to/url"
},
"license":"MIT",
"engines": {"node": "0.10.x"},
"bugs":{"url":"http://path/to/bug","email":"bug@example.com"},
"contributors":[{"name":"李四","email":"lisi@example.com"}],
"scripts": { #npm脚本
"start": "node index.js"
},
"dependencies": { #项目运行依赖
"express": "latest",#安装最新版本
"mongoose": "~3.8.3", # ~表示安装3.8.x的最新版本(不低于3.8.3)
"handlebars-runtime": "^1.0.12", # ^表示安装1.x.x最新版本(不低于1.0.12)
"express3-handlebars": "~0.5.0",
"MD5": "~1.2.0"
},
"devDependencies": {
"bower": "~1.2.8",
"grunt": "~0.4.1",
"grunt-contrib-concat": "~0.3.0",
"grunt-contrib-jshint": "~0.7.2",
"grunt-contrib-uglify": "~0.2.7",
"grunt-contrib-clean": "~0.5.0",
"browserify": "2.36.1",
"grunt-browserify": "~1.3.0",
} #项目开发依赖
}
package-lock.json
package-lock.json 是在安装项目依赖项时自动生成的锁定文件。
它记录了精确的依赖项版本,以及它们的完整依赖树结构。它还包含了每个依赖项的下载地址,以及安装时间戳等信息。
package-lock.json 的目的
- npm install 会默认下载包的最新版本,
package-lock.json
锁定版本号,使得 npm 默认下载记录在册的版本的包,防止自动升级; - 确保在不同的环境下,安装的依赖项保持一致性,避免因为依赖项的不一致导致的构建失败或运行时错误。
npm script
scripts指npm命令的缩写,比如start指定了npm run start所要执行的命令
"scripts": {
"preinstall": "echo here it comes!",
"postinstall": "echo there it goes!",
"start": "node index.js",
"test": "tap test/*.js"
}
转载自:https://juejin.cn/post/7401027594231463976