Node 总起
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
Node 运行 JS
安装:
- 建议安装到默认位置,并勾选“自动安装必要工具”
node -v
,出现版本号,即表示安装成功
运行:
- 打开终端,定位脚本文件的所属目录
- 输入
node 文件名
执行对应的文件 - 注意:文件名不要用
node.js
来命名,也最好不要使用中文和空格
npm start
- 如下代码定义了一个
start
脚本,运行npm start
时会调用它来启动服务器。npm start
实际上运行了node ./bin/www
- 文件
/bin/www
是应用入口。它做的第一件事是 require 真实的应用入口(项目根目录中的app.js
) npm run devstart
运行nodemon ./bin/www
json 代码解读复制代码"scripts": {
"start": "node ./bin/www",
"devstart": "nodemon ./bin/www"
},
核心模块
文件读写模块
fs(file-system)
核心模块,提供了所有文件操作相关的API
(1)文件读取
JavaScript 代码解读复制代码// 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)文件写入
JavaScript 代码解读复制代码// 1.引入fs核心模块
var fs = require('fs');
// 2.将数据写入文件
fs.writeFile('./data/a.txt','我是文件写入的信息',function(err,data){
if(err){
console.log('文件写入失败');
}
else{
console.log(data.toString());
}
})
http 服务器
JavaScript 代码解读复制代码// 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...')
})
path 操作模块
path.basename
:获取路径的文件名,默认包含扩展名path.dirname
:获取路径中的目录部分path.extname
:获取路径中的扩展名部分path.parse
:把路径转换为对象path.join
:拼接路径path.isAbsolute
:判断一个路径是否为绝对路径
模块化
(1)模块化编程:
- 不同功能的代码分离到不同的模块中
- 一个干净的主文件(index.js)+ 好维护可复用的干净的模块
(2)通过 script 标签实现的模块化
- 没办法按需引入
- 模块间的相互依赖关系往往非常复杂,必须要按顺序引入
node 中的模块
-
核心模块
fs
文件操作http
http服务操作模块url
路径操作模块path
路径处理模块os
操作系统信息
-
第三方模块: 通过npm下载
-
自定义模块 : 自己创建的 js 文件
CommonJs 重试 错误原因
CommonJs 是 Node.js 中默认使用的模块化标准。
- 模块就是一个js文件,拥有模块作用域,模块内部变量是私有的,外部无法访问。避免变量命名冲突污染的问题
- CommonJS模块内部定义了一个
module
对象,其存储了当前模块的基本信息 - module对象用
exports
属性 指定需要向外部暴露的内容 - 其他模块通过
require
来获取这些暴露的内容
「 Node.js会将以下内容视为CommonJS模块 」
.cjs
文件- 默认情况下的
.js
文件(未设置package.json
的type
属性)
加载require
重试 错误原因
(1) 核心模块
核心模块本质也是 JS 文件,通过暴露了一个对象来提供一些方法
核心模块文件已经被编译到了 node 的可执行程序文件中,只需要按照名字加载
(2) 第三方模块: 先通过 npm 下载,然后require('包名')
来加载
JavaScript 代码解读复制代码// 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的顺序寻找主文件。
导出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
)
JavaScript 代码解读复制代码//导出单个/多个内容--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 };
模块的包装
每一个 CommonJS 模块在执行时,外层都会被套上一个函数
在模块里console.log(arguments)
就能查看到
JavaScript 代码解读复制代码(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
__dirname
和__filename
- 不受 node 命令所属路径影响
- 全局变量,可以在任何模块中直接使用,无需额外引入
- 模块中的路径标识(
require(...)
)相对于当前文件模块,不受node命令所处路径影响 - 而文件操作路径(如读取/写入文件等)默认是相对于 Node.js 命令所处的路径。因此,文件操作中使用相对路径是不安全的,建议统一用以上两个成员
JavaScript 代码解读复制代码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);
});
ES6 模块化
ES6 模块化用import()
方法
「 Node.js 默认用的是 CommonJs,想要使用 ES 模块化 」
- 方式一,直接将所有的 js 文件修改为 mjs 扩展名
- 方式二,修改 package.json 中 type 属性为 module(默认是 commonjs)
【注意】
- ES 模块的官方标准不能省略拓展名
- ES 模块导入的内容都是常量,不能随便赋值
- 一个模块只有一个默认导出,默认导出的只能是一个值(对象/函数/类/数值…),不能是语句
- 引入默认导出不需要
{}
;可以随意取名。 - 尽量避免全部导入,影响打包性能使得项目臃肿,推荐按需导入
- ES 模块都是运行在严格模式下的
- ES 模块化在浏览器中也可以使用,但是一般不直接用,而是结合打包工具用
JavaScript 代码解读复制代码// 导出变量(命名导出)
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 …;
JavaScript 代码解读复制代码// 引入默认导出,不需要{},可以随意取名
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";
```。