赞
踩
● node.js
是一个开发平台,就像 JAVA
开发平台、.net
开发平台、PHP
开发平台
开发平台有对应的编程语言、有语言运行时、有能实现特性功能的 API
(SDK
:Software Development Kit)
● 该平台使用的编程语言是 JavaScript
●node.js
平台基于 chrome VB JavaScript
引擎构建
● 基于 node.js
可以开发控制台程序(命令行程序、CLI程序)、桌面应用程序(GUI)(借助 node-webkit
、electron
等框架实现)、Web应用程序(网址)
● node.js
全站开发技术栈:MEAN -- MongoDB Express Angular Node.js
I/O
模型(当执行 I/O
操作时,不会阻塞线程)npm
Node
版本管理)nvm
(Linux
, Unix
, OS X
)nvm install node
(安装最新版本的 node
)nvm use node
(使用指定版本的 node
)nvm-windows
(Windows)nvm version
nvm install latest
nvm install 版本号
nvm uninstall 版本号
nvm list
:查看安装信息nvm use 版本号
● 传统 PHP等开发网站:
● node.js
开发网站
例如:卸载 express 模块
npm uninstall express
卸载后,可以到 /node_modules/ 目录下查看包是否还存在,或者使用以下命令查看:
npm ls
例:更新 express 模块
npm update express
例:搜索 express 模块
npm search express
1、创建模块,package.json 文件是必不可少的。
npm init
2、在 npm 资源库中创建用户(使用邮箱注册):
npm adduser
3、发布模块
npm publish
npm unpublish <package>@<version> # 可以撤销发布自己发布过的某个版本代码
NPM 使用语义版本号来管理代码。语义版本号分为 X.Y.Z 三位,分别代表主版本号、次版本号和补丁版本号。 当代码变更时,版本号按以下原则更新。
除了可依赖一个固定版本号外,还可依赖于某个范围的版本号。例如 “argv”:“0.0.x” 表示依赖于0.0.x系列的最新版 argv
REPL
全称:Read-Eval-Print-Loop(交互式解释器)R
读取 - 读取用户输入,解析输入了JavaScript数据结构并存储在内存中E
执行 - 执行输入的数据结构P
打印 - 输出结果L
循环 - 循环操作以上步骤直到用户两次按下 ctrl-c 按钮退出Control + C
退出 REPL 界面 或者 输入 .exit
退出 REPL 界面变量声明需要使用 var 关键字,如果没有使用 var 关键字变量会直接打印出来
使用 var 关键字的变量可以使用 console.log()
来输出变量
> x = 10
10
> var y = 10
undefined
> x + y
20
(_
) 获取表达式的运算结果:
> var x = 10
undefined
> var y = 10
undefined
> x + y
20
> var sum = _
undefined
> console.log(sum);
30
undefined
ctrl + c
- 退出当前终端ctrl + c 按下两次
- 退出 Node REPLctrl + d
- 退出 Node REPL向上/向下 键
- 查看输入的历史命令tab 键
- 列出当前命令.help
- 列出使用命令.break
- 退出多行表达式.clear
- 退出多行表达式.save filename
- 保存当前的 Node REPL 会话到指定文件.load filename
- 载入当前 Node REPL 会话的内容Node.js 异步编程的直接体现就是回调。
异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了。
回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都支持回调函数。
回调函数一般作为函数的最后一个参数出现,回调函数接收错误对象作为第一个参数:
function foo1(name, age, callback) { }
function foo2(value, callback1, callback2) { }
阻塞是按顺序执行的,非阻塞是不需要按顺序执行的。
fs.readFileSync()
fs.readFile()
// input.txt
这是一段文字!!!
// 1.js
var fs = require('fs');
var data = fs.readFileSync('input.txt');
console.log(data.toString());
console.log('程序执行结束!');
执行结果:
> node 1.js
这是一段文字!!!
程序执行结束!
// 1.js
var fs = require('fs');
fs.readFile('input.txt', function(err, data) {
if(err) return console.error(err);
console.log(data.toString());
});
console.log('程序执行结束!');
执行结果:
> node 1.js
程序执行结束!
这是一段文字!!!
Node.js 使用事件驱动模型,当 web server 接收到请求,就把它关闭然后进行处理,然后去服务下一个 web 请求。
当这个请求完成,它就被放回处理队列,当到达队列开头,这个结果被返回给用户。
webserver 一直接受请求而不等待任何读写操作。(这也称之为非阻塞式IO或者事件驱动IO)
在事件驱动模型中,会生成一个主循环来监听事件,当检测到事件时触发回调函数。
Node.js所有的异步I/O操作在完成时都会发送一个事件到事件队列。
Node.js里面的许多对象都会分发事件:一个 net.Server 对象会在每次有新连接时触发一个事件,一个 fs.readStream
对象会在文件被打开的时候触发一个事件。所有这些产生事件的对象都是 event.EventEmitter
的实例。
EventEmitter 的核心就是事件触发与事件监听器功能的封装。可以通过require("events")
来访问这个模块
EventEmitter
对象如果在实例化时发生错误,会触发 error
事件。当添加新的监听器时,newListener
事件会触发,当监听器被移除时,removeListener
事件被触发。
// 引入 events 模块
const events = require('events');
// 创建 eventEmitter 对象
const eventEmitter = new events.EventEmitter();
// 绑定事件及事件的处理程序
eventEmitter.on('eventName', eventHandler);
// 触发事件
eventEmitter.emit('eventName');
// 菜鸟例子----main.js // 引入 events 模块 const events = require('events'); // 创建 eventEmitter 对象 const eventEmitter = new events.EventEmitter(); // 创建事件处理程序 const connectHandler = function connected() { console.log("连接成功!"); // 触发 data_received 事件 eventEmitter.emit('data_received'); } // 绑定 connection 事件处理程序 eventEmitter.on('connection', connectHandler); // 使用匿名函数绑定 data_received 事件 eventEmitter.on('data_received', function() { console.log('数据接收成功。') }) // 触发 connection 事件 eventEmitter.emit('connection'); console.log('程序执行完毕');
EventEmitter
的每个事件由一个事件名和若干个参数组成,事件名是一个字符串,通常表达一定的语义。对于每个事件,EventEmitter
支持若干个事件监听器。
当事件触发时,注册到这个事件的事件监听器被依次调用,事件参数作为回调函数参数传递。
const events = require("events");
const eventsEmitter = new events.EventEmitter();
eventsEmitter.on("func_name", function() {
console.log("这是监听1");
});
eventsEmitter.on('func_name', function(arg1, arg2) {
console.log("这是监听2");
console.log("arg1", arg1);
console.log("arg2", arg2);
})
eventsEmitter.emit("func_name", "参数1", "参数2");
addListener(event, listener)
:为指定事件添加一个监听器到监听器数组的尾部
on(event, listener)
:为指定事件注册一个监听器,接受一个字符串 event 和一个回调函数
once(event, listener)
:为指定事件注册一个单次监听器,即 监听器最多只会触发一次,触发后立刻解除该监听器
removeListener(event, listener)
:移除指定事件的某个监听器,监听器必须是该事件已经注册过的监听器。它接受两个参数,第一个是事件名称,第二个回调函数名称
removeAllListeners([event])
:移除所有事件的所有监听器,如果指定事件,则移除指定事件的所有监听器
sexMaxListeners(n)
:默认情况下,EventEmitters 如果你添加的监听器超过 10 个就会输出警告信息。 setMaxListeners 函数用于改变监听器的默认限制的数量。
listeners(event)
:返回指定事件的监听器数组
emit(event, [arg1], [arg2], [...])
:按监听器的顺序执行每个监听器,如果事件有注册监听返回 true,否则返回 false
listenerCount(emitter, event)
:返回指定事件的监听器数量。
events.emitter.listenerCount(eventName);
全局模块可以直接使用,而非全局模块需要先通过 require('')
加载该模块。
fs
模块是 Node.js 官方提供的,用来操作文件的模块。它提供了一系列的方法和属性,用来满足用户对文件的操作需求。
fs.readFile(path, [, options], callback)
方法,用来读取指定文件中的内容
fs.writeFile()
方法,用来向指定的文件中写入内容const fs = require('fs')
例子:
// fs.js // 执行文件操作 // 实现文件写入操作 // 1.加载文件操作模块: fs 模块 var fs = require('fs'); // 2.实现文件写入操作 let msg = 'hello world, 你好世界!'; // 3.调用 fs.writeFile() 进行文件写入 // fs.writeFile(file, data[, options], callback) fs.writeFile('./hello.txt', msg, 'utf-8', function(err) { // 如果 err === null,表示写入文件成功,没有错误! // 只要 err 里面不是 null,就表示写入文件失败! if(err) { console.log('写文件失败!具体错误为:', err); } else { console.log('写入成功啦!') } }) // 读取文件 // 如果传递了编码(utf8),那么回调函数中的 data 默认就会转换为字符串,没有的话则为一个 Buffer 对象,需要将 buffer 对象转换为字符串,调用 toString()方法 fs.readFile('./hello.txt', 'utf8', function(err, msg) { if(err) { throw err; } })
node.js
中单线程-非阻塞IO
解释JavaScript V8
引擎:堆和调用栈
浏览器:
__dirname
和 __filename
__dirname
: 当前正在执行的 js 文件所在的目录__filename
:当前正在执行的 js 文件的完整路径__dirname
和 __filename
并不是全局的
/* * 此处的 ./ 相对路径,相对的是执行 node 命令的路径 * 而不是相对于正在执行的这个 js 文件来查找 hello.txt */ fs.readFile('./hello.txt', 'utf8', function(err, msg) { if(err) { throw err; } }); // 解决方案: // __dirname: 当前正在执行的 js 文件所在的目录 // __filename:当前正在执行的 js 文件的完整路径 // __dirname 和 __filename 并不是全局的 var filename = __dirname + '\\' + 'hello.txt'; fs.readFile(filename, 'utf8', function(err, msg) { if(err) { throw err; } });
var path = require('path');
var filename = path.join(__dirname, 'hello,txt');
fs.readFile(filename, 'utf8', function(err, msg) {
if(err) {
throw err;
}
});
request
(http.IncomingMessage
)和 response
(ServerResponse
)request
:服务器解析用户提交的http
请求报文,将结果解析到request
对象中,凡是要获取和用户相关的数据都可以通过 request 对象获取
request
对象类型 <http.IncomingMessage>
,继承自 stream.Readable
request
对象常用成员request.header
:返回的是一个对象,这个对象包含了所有的请求报文头request.rawHeaders
:返回的是一个数组,数组中保存的都是请求报文头的字符串request.httpVersion
:获取请求客户端所使用的 http
版本request.method
:获取客户端请求使用的方法(post
、get
…)request.url
:获取这次请求的路径(获取请求报文中的请求路径,不包含主机名称、端口号、协议) response
:在服务器端用来向用户做出响应的对象,凡是需要向用户(客户端)响应的操作,都需要通过 response
对象来进行http
模块构建一个简单的 http
服务程序// 1.加载 http 模块 var http = require('http'); // 2.创建一个 http 服务对象 var server = http.createServer(); // 3.监听用户的请求事件(request 事件) // request 对象包含了用户请求报文中的所有内容,通过 request 对象可以获取所有用户提交过来的数据 // response 对象用来向对象响应一些数据,当服务器要向客户端响应数据的时候必须使用 response 对象 server.on('request', function(request, response) { // body... // 解决乱码的思路:服务器通过设置 http 响应报文头,告诉浏览器使用相应的编码来解析 response.setHeader('Content-Type', 'text/plain;charset=utf-8') response.write('hello world!'); // 对于每一个请求,服务器必须结束响应,否则客户端(浏览器)会一直等待服务器响应结束 response.end(); }) // 4.启动服务 server.listen(8080, function() { console.log('服务器启动了,请访问 http://localhost:8080') })
var http = require('http'); http.createServer(function(req, res) { // body... // 获取用户请求的路径 req.url // console.log(req.url); // 结束响应 // res.end(); req.setHeader('Content-Type', 'text/plain;charset=utf-8'); if(req.url === '/' || req.url === '/index') { res.end('Hello Index'); } else if(req.url=== '/login') { res.end('hello login') } else if(req.url === "/images/index.png") { fs.readFile(path.join(__dirname, 'images', 'index.png'), function(err, data) { // image // body... res.setHeader('Content-Type', 'text/css'); res.end(data); }) }else if(req.url === '/css/index.css') { // css fs.readFile(path.join(__dirname, 'css', 'index.css'), function(err, data) { res.setHeader('Content-Type', 'text/css'); res.end(data); } ) } }).listen(8080, function() { console.log('http://localhost:8080') })
var http = require('http'); var fs = require('fs'); var path = require('path') http.createServer(function(req, res) { // body... // 获取用户请求的路径 req.url // console.log(req.url); // 结束响应 // res.end(); req.setHeader('Content-Type', 'text/plain;charset=utf-8'); if(req.url === '/' || req.url === '/index') { fs.readFile(path.join(__dirname, 'htmls', 'index.html'), function(err, data) { if(err) { throw err } res.end(data); }) } }).listen(8080, function() { console.log('http://localhost:8080') })
try-catch
与 异步操作nodeJS
:只能捕获同步操作的异常,对于异步操作的异常是无法捕获的。对于异步操作,要通过判断错误号(err.code
)来进行错误处理
在请求服务器的时候,请求的 url 就是一个标识
response.setHeader
和 response.writeHead
response.setHeader(name, value)
为header
对象设置一个单一的header
值。如果该header
已经存在了,则将会被替换。
response.writeHead(statusCode[, statusMessage][, headers])
HTTP
状态码,如404
statusMessage
是可选的状态描述headers
是响应头response.end()
被调用之前调用setHeader
只可以设置一个 header
,但是 writeHead
可以设置多个 headers
,其中第一个是状态码,第二个是包含 headers
的对象。
当使用 response.setHeader()
设置响应头时,它们将与传给 response.writeHead()
的任何响应头合并,其中 response.writeHead()
的响应头优先。
浏览器路由跳转
var list = [];
list.push(urlObj.query); // 要写入 data.json 数据
// 将数据写入 data.json 文件
fs.writeFile(path.join(__dirname, "data", 'data.json'), JSON.stringify(list), function(err) {
if(err) {
throw err;
}
console.log("OK");
// 设置响应报文头,通过响应报文头告诉浏览器,执行一次页面跳转操作
// 重定向
res.statusCode = 302; // 状态码
res.statusMessage = "Found"; // 状态信息
res.setHeader("Location", "/"); // 设置响应报文头
res.end(); // 每次请求都要写--结束响应
})
GET
方式提交先判断文件是否存在数据,如果存在则先读取文档数据(防止数据被覆盖),再将新增数据与原有数据一起写到文件中
// 读取 data.json 文件中的数据,并将读取到的数据转换为一个数组 // 此处,读取文件的时候可以直接写一个 utf8 编码,回调函数中的 data 就是一个字符串了 fs.readFile(path.join(__dirname, "data", "data.json", "utf-8", function(err, data) { // 因为第一次访问网站,data.json 文件本身就不存在,所以肯定是有错误的 // 但是这种错误,我们并不认为是网站出错了,所以不需要抛出异常 if(err && err.code !== 'ENOENT') { throw err; } // 如果读取到数据了,那么就把读取到的数据 data,转换为 list 数组 // 如果没有读取到数据,那么就把 '[]' 转换为数据 var list = JSON.parse(data || '[]'); // 向数组对象 list 中 push 一条新闻 list.push(urlObj.query); var list = []; list.push(urlObj.query); // 要写入 data.json 数据 // 将数据写入 data.json 文件 fs.writeFile(path.join(__dirname, "data", 'data.json'), JSON.stringify(list), function(err) { if(err) { throw err; } console.log("OK"); // 设置响应报文头,通过响应报文头告诉浏览器,执行一次页面跳转操作 // 重定向 res.statusCode = 302; // 状态码 res.statusMessage = "Found"; // 状态信息 res.setHeader("Location", "/"); // 设置响应报文头 res.end(); // 每次请求都要写--结束响应 }) }))
POST
方式提交因为post
提交数据的时候,数据量可能比较大,所以会分多次进行提交,每次提交一部分数据。
此时要想在服务器中获取用户提交的所有数据,就必须监听request
事件的data
事件。
req.on("data", function(chunk) {
})
chunk
就是浏览器本次提交过来的一部分数据chunk
的数据类型是Buffer
(chunk
就是一个Buffer
对象)当request
对象的end
事件被触发的时候,浏览器把所有数据都提交到服务器了。
req.on("end", function() {
// 在这个事件中只要把 array 中的所有数据汇总起来就好了
})
var querystring = require('querystring'); // 读取 data.json 文件中的数据 fs.readFile(path.join(__dirname, "data", "data.json", "utf-8", function(err, data) { if(err && err.code !== 'ENOENT') { throw err; } var list = JSON.parse(data || '[]'); var array = []; req.on("data", function(chunk) { array.push(chunk); }); // 监听 request 对象的 end 事件 // 当 end 事件被触发的时候,表示上述所有数据都已经提交完毕了 req.on("end", function() { // 在这个事件中只要把 array 中的所有数据汇总起来就好了 // 把 array 中的每个 buffer 对象,集合起来转换为一个 buffer 对象 var postBody = Buffer.concat(array); // 把获取到的 buffer 对象转换为一个字符串 postBody = postBody.toString('utf8'); // 把 post 请求的查询字符串,转换为一个 json 对象 postBody = querystring.parse(postBody); // 将用户提交的新闻 push 到 list 中 list.push(postBody); // 将新的 list 数组,再写入到 data.json 文件中 // 将数据写入 data.json 文件 fs.writeFile(path.join(__dirname, "data", 'data.json'), JSON.stringify(list), function(err) { if(err) { throw err; } console.log("OK"); // 设置响应报文头,通过响应报文头告诉浏览器,执行一次页面跳转操作 // 重定向 res.statusCode = 302; // 状态码 res.statusMessage = "Found"; // 状态信息 res.setHeader("Location", "/"); // 设置响应报文头 res.end(); // 每次请求都要写--结束响应 }) }) }))
module
模块和package
包的区别1、A module is any file or directory that can be loaded by Node.js’ require()
.
模块可以是任何一个文件或目录(目录下可以有很多个文件),只要能被node.js
通过require()
即可。
2、A package is a file or directory that is described by a package.json
. This can happen in a bunch of different ways!
包是一个文件或目录(目录下可以有多个文件)必须有一个package.json
文件来描述,就可以是一个包。
package.json
文件package.json
文件是一个包说明文件(项目描述文件),用来管理组织一个包(一个项目)package.json
文件是一个json
格式的文件name
*:包的名字version
*:包的版本description
:包描述homepage
:包的官网 urlauthor
:包的作者contributors
:包的其他贡献者姓名dependencies
:依赖包列表。如果依赖包没有安装,npm 会自动将依赖包安装在 node_module 目录下main
:程序的主入口文件。包的入口js
文件,从main
字段这里指定的那个js
文件开始执行repository
:包代码存放的地方的类型,可以是 git 或 svn,git 可在 Github 上keywords
:关键字package-lock.json
文件该文件旨在跟踪被安装的每个软件包的确切版本,以便产品可以以相同的方式被100%复制(即使软件包的维护者更新了软件包)。
这解决了 package.json
一直尚未解决的特殊问题。 在 package.json
中,可以使用 semver
表示法设置要升级到的版本(补丁版本或次版本),例如:
〜0.13.0
,则只更新补丁版本:即 0.13.1
可以,但 0.14.0
不可以。^0.13.0
,则要更新补丁版本和次版本:即 0.13.1
、0.14.0
、依此类推。0.13.0
,则始终使用确切的版本。可能是你,或者是其他人,会在某处尝试通过运行 npm install
初始化项目。
因此,原始的项目和新初始化的项目实际上是不同的。 即使补丁版本或次版本不应该引入重大的更改,但还是可能引入缺陷。
package-lock.json
会固化当前安装的每个软件包的版本,当运行 npm install
时,npm
会使用这些确切的版本。
package-lock.json
文件需要被提交到 Git
仓库,以便被其他人获取(如果项目是公开的或有合作者,或者将 Git
作为部署源)。
当运行 npm update
时,package-lock.json
文件中的依赖的版本会被更新。
Underscore 一个 JavaScript 实用库,提供了一整套函数式编程的实用功能,但是没有扩展任何 JavaScript 内置对象。它弥补了部分 jQuery 没有实现的功能,同时又是 Backbone.js 必不可少的部分。
npm install underscore
_.zip(*arrays)
和_.unzip(array)
–数组(Arrays
)_.zip(*arrays)
:将每个 arrays
中相应位置的值合并在一起。 当您有通过匹配数组索引进行协调的独立数据源时,这非常有用。_.unzip(array)
:给定若干 arrays
,返回一串联的新数组,其第一元素个包含所有的输入数组的第一元素,其第二包含了所有的第二元素,依此类推。const _ = require('underscore'); // 引用
const names = ['张三', '李四', '王五'];
const ages = [23,43,55];
const genders = ['女', '男', '男'];
const result = _.zip(names, ages, genders); // 压缩
console.log(result);
const result1 = _.unzip(result); // 解压缩
console.log(result1);
template
–工具函数(Utility
)_.template(templateString, [settings])
:将 JavaScript
模板编译为可以用于页面呈现的函数, 对于通过 JSON
数据源生成复杂的 HTML
并呈现出来的操作非常有用。
<%= … %>
插入变量, 也可以用<% … %>
执行任意的 JavaScript 代码。HTML
转义,请使用<%- … %>
。data
对象 。data
作为第二个参数给模板 template
来直接呈现, 这样页面会立即呈现而不是返回一个模板函数.settings
是一个哈希表包含任何可以覆盖的设置 _.templateSettings
.const _ = require("template");
// 声明了一段模板代码的 html 文档
let html = '<h2><%= name %></h2>'; // 有可能是完整的复杂的 html 文档
// template() 函数返回依然是一个函数
const fn = _.template(html);
// 调用 template() 返回的这个函数 fn
// fn 接受一个数据对象,并用该数据对象,将 html 中的模板内容替换,生成最终的 html 代码
html = fn({name: '哈哈哈哈'});
console.log(html);
执行结果:
html
中的模板html
文档
index.js
文件
异步函数有数据返回,可以用回调函数:
node.js
中的模块核心模块(Core Module),也称内置模块、原生模块
fs
http
path
url
...
node.js
的时候就已经编译成二进制文件,可以直接加载运行(速度较快)node.exe
这个进程启动的时候就已经默认加载了,所以可以直接使用按文件后缀来分
如果加载时,没有指定后缀名,那么就按照如下顺序依次加载相应模块
.js
.json
.node
(C
/C++
编写的模块)mime
cheerio
moment
mongo
...
require()
require()
引用情况require()
的参数是一个路径(相对或者绝对路径)require("./index2.js");
require('./index2');
/*
* 没有写后缀名的时候:
* 系统首先会找 index2.js 文件;
* 如果没有 index2.js 文件,
* 就会找 index2.json 文件;
* 如果没有 index2.json 文件,
* 系统会找 index2.node 文件;
* 都没有就会想 是不是文件夹(index2 文件夹) --> 第三方模块 --> package.json 文件 --> main(入口文件 app.js --> index.js/index.json/index.node) --> 加载失败
*/
require()
的参数不是路径,直接就是一个模块名称require('http')
js
文件所在的目录下去找是否有一个node_modules
文件夹require("mime");
require
加载模块注意点require
加载模块是同步的node.js
加载模块的规则去查找node.js
源码编译的时候,都已经编译为二进制执行文件,所以加载速度较快(核心模块
加载的优先级仅次于 缓存加载
)lib
目录下核心模块
同名的自定义模块(第三方模块)
是不会成功的核心模块
只能通过 模块名称
来加载require('./http');
这样是无法加载核心模块 http
的require()
加载模块使用./
相对路径时,相对路径是相对当前模块,不受执行node
命令的路径影响文件模块
的时候始终添加文件后缀名,不要省略module.exports
一个模块,默认被require()
加载后,返回的是一个空对象{}
// a.js
var b = require("./b.js");
console.log(b);
// b.js
console.log('2aaaa')
如果要返回其他类型,需要引用module.exports
// b.js
module.exports.name = "张三";
module.exports.age = 23;
module.exports.show = function() {
console.log(this.name,"今年",this.age,"岁了");
}
this.show();
// a.js
var b = require("./b.js");
console.log(b);
module.exports
和exports
exports
变量在模块的文件级作用域内可用,并在评估模块之前被分配 module.exports
的值。
它允许一个快捷方式,以便 module.exports.f = ...
可以更简洁地写成 exports.f = ...
。
但是,请注意,与任何变量一样,如果将新值分配给 exports,则它就不再绑定到 module.exports
:
module.exports.hello = true; // 从模块的 require 中导出
exports = { hello: false }; // 未导出,仅在模块中可用
当 module.exports
属性被新对象完全替换时,通常也会重新分配 exports
:
module.exports = exports = function Constructor() {
// ... 等等。
};
为了阐明该行为,想象一下 require()
的这个假设实现,它与 require()
的实际实现非常相似:
function require(/* ... */) {
const module = { exports: {} };
((module, exports) => {
// 模块代码在这里。 在本例中,定义一个函数。
function someFunc() {}
exports = someFunc;
// 此时,exports 不再是 module.exports 的快捷方式,
// 并且此模块仍然会导出空的默认对象。
module.exports = someFunc;
// 此时,该模块现在将导出 someFunc,
// 而不是默认对象。
})(module, module.exports);
return module.exports;
}
通过b.js
不同情况进行分析,a.js
文件不变
// a.js
const b = require('./b.js');
console.log(b);
b.js
原始文件:// b.js
module.exports.name = "张三";
exports.age = 10;
exports.show = function() {
console.log(this.name + ":" + this.age);
}
module.exports
输出字符串// b.js
module.exports.name = "张三";
exports.age = 10;
exports.show = function() {
console.log(this.name + ":" + this.age);
}
module.exports = "Hello world!";
最终require()
函数返回的是module.exports
中的数据return module.exports;
–>输出内容被替换了:
exports
输出一个字符串// b.js
module.exports.name = "张三";
exports.age = 10;
exports.show = function() {
console.log(this.name + ":" + this.age);
}
exports = "Hello world!";
输出结果:
exports
指向变了,module.exports
指向没变。由于return module.exports
,所以输出还是对象
JavaScript 只有字符串数据类型,没有二进制数据类型。
Node.js 定义了一个 Buffer
类,该类用来创建一个专门存放二进制数据的缓存区,用来处理像 TCP流或文件流这种必须使用到二进制数据。
Buffer
实例一般用于表示编码字符的序列,比如 UTF-8
、 UCS2
、 Base64
、或十六进制编码的数据。 通过使用显式的字符编码,就可以在 Buffer
实例与普通的 JavaScript 字符串之间进行相互转换。
// 例子
const buf = Buffer.from("测试文字", 'ascii');
console.log(buf.toString('hex'));
console.log(buf.toString('base64'));
Buffer.alloc(size[, fill[, encoding]])
:返回一个指定大小的 Buffer 实例,如果没有设置 fill,则默认填满0Buffer.allocUnsafe(size)
:返回一个指定大小的 Buffer 实例,但是它不会被初始化,所以它可能包含敏感的数据Buffer.allocUnsafeSlow(size)
:不从 buffer 缓冲区里分配,直接从操作系统分配,slow 指的是没有从缓冲池高效分配Buffer.from(array)
: 返回一个被 array 的值初始化的新的 Buffer 实例(传入的 array 的元素只能是数字,不然就会自动被 0 覆盖)Buffer.from(arrayBuffer[, byteOffset[, length]])
: 返回一个新建的与给定的 ArrayBuffer 共享同一内存的 Buffer。Buffer.from(buffer)
: 复制传入的 Buffer 实例的数据,并返回一个新的 Buffer 实例Buffer.from(string[, encoding])
: 返回一个被 string 的值初始化的新的 Buffer 实例buf.write(string[, offset[, length]][, encoding]);
返回:
实际写入的大小。如果 buffer 空间不足,则只会写入部分字符串。
参数:
string-写入缓冲区的字符串
offset-缓冲区开始写入的索引值,默认为0
length-写入的字节数,默认为buffer.length
encoding-使用的编码。默认为'utf8'
根据 encoding
的字符编码写入 string
到 buf
中的 offset
位置。length
参数是写入的字节数。 如果 buf
没有足够的空间保存整个字符串,则只会写入 string
的一部分。 只部分解码的字符不会被写入。
const buf = Buffer.alloc(10);
len = buf.write("这是一条测试语句!", 'utf8');
console.log("写入的字节数:", buf, len);
buf.toString([encoding[, start[, end]]])
参数:
encoding - 使用的编码。默认为 'utf8' 。
start - 指定开始读取的索引位置,默认为 0。
end - 结束位置,默认为缓冲区的末尾。
返回值:
解码缓冲区数据并使用指定的编码返回字符串
Get
和Post
请求req.on('data')
:响应数据上传的事件,并对数据进行收集。req.on('end')
:响应数据上传结束的事件,并判断是否存在上传数据。如果存在,则执行后续逻辑。const http = require("http"); const server = http.createServer((req, res)=>{ let postData = ""; req.on("data", (chunk)=>{ postData += chunk.toString(); }) req.on('end', ()=>{ if(postData) { res.setHeader("content-type", "application/json"); res.end(postData) } }) }) server.listen(8600, ()=>{ console.log("8600 is running!") })
node:querystring
模块提供了用于解析和格式化网址查询字符串的实用工具。
const http = require("http");
const querystring = require("querystring");
const server = http.createServer((req, res)=>{
const param = req.url.split("?");
req.query = {};
if(param && param.length>0) {
if(param[1]) {
req.query = querystring.parse(param[1]);
}
}
res.end(JSON.stringify(req.query))
}).listen(9999, ()=>{
console.log("9999 is running!");
})
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。