likes
comments
collection
share

Node | 入门知识梳理Node.js入门知识梳理。Node.js 是 JavaScript 运行环境,使得 JS

作者站长头像
站长
· 阅读数 18

1 Node 总起

1.1 Node.js是什么
  1. Node.js 是 JavaScript 运行环境,使得 JS 可以运行在浏览器以外的地方
  2. 单线程,通过异步的方式来处理并发的问题
  3. 「浏览器中的 JS VS Node.js 中的 JS」
  • 基本语法一致,ECMAScript
  • Node 没有 Bom、Dom
  • Node 环境为 JavaScript 提供了一些服务器级别的API
    • 文件的读写
    • 网络通信、http服务
  1. 构建于 Chrome 的 V8 引擎之上
  • 引擎:用于解析和执行 JS 代码,V8 是目前公认最快引擎
  • Node 作者把 V8 引擎移植出来,开发了一个独立的 JavaScript 运行时环境
  1. 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 相关的包
  1. Node能做什么
  • Web服务器后台
  • 命令行工具 :npm下载包,npm install jquery
1.2 Node 运行 JS

安装

  1. 建议安装到默认位置,并勾选“自动安装必要工具”
  2. node -v,出现版本号,即表示安装成功

运行:

  1. 打开终端,定位脚本文件的所属目录
  2. 输入node 文件名执行对应的文件
  3. 注意:文件名不要用node.js来命名,也最好不要使用中文和空格
1.3 npm start
  1. 如下代码定义了一个start脚本,运行 npm start时会调用它来启动服务器。npm start 实际上运行了node ./bin/www
  2. 文件 /bin/www是应用入口。它做的第一件事是 require 真实的应用入口(项目根目录中的 app.js
  3. 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 操作模块

参考文档:nodejs.org/docs/latest…

  • path.basename:获取路径的文件名,默认包含扩展名
  • path.dirname:获取路径中的目录部分
  • path.extname:获取路径中的扩展名部分
  • path.parse:把路径转换为对象
  • path.join:拼接路径
  • path.isAbsolute:判断一个路径是否为绝对路径

3 模块化

(1)模块化编程

  • 不同功能的代码分离到不同的模块中
  • 一个干净的主文件(index.js)+ 好维护可复用的干净的模块

(2)通过 script 标签实现的模块化

  • 没办法按需引入
  • 模块间的相互依赖关系往往非常复杂,必须要按顺序引入
3.1 node 中的模块
  • 核心模块
    • fs文件操作
    • httphttp服务操作模块
    • url路径操作模块
    • path路径处理模块
    • os操作系统信息
  • 第三方模块: 通过npm下载
  • 自定义模块 : 自己创建的 js 文件
3.2 CommonJs

CommonJs 是 Node.js 中默认使用的模块化标准

  • 模块就是一个js文件,拥有模块作用域,模块内部变量是私有的,外部无法访问。避免变量命名冲突污染的问题
  • CommonJS模块内部定义了一个module对象,其存储了当前模块的基本信息
  • module对象用 exports 属性 指定需要向外部暴露的内容
  • 其他模块通过require来获取这些暴露的内容

「 Node.js会将以下内容视为CommonJS模块 」

  • .cjs文件
  • 默认情况下的.js文件(未设置package.jsontype属性)
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 存储包文件的服务器在国外,下载速度很慢。 淘宝的开发团队在国内做了一个镜像:

developer.aliyun.com/mirror/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

npm scripts 使用指南 - 阮一峰的网络日志

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
评论
请登录