Node.js学习笔记 四

Node.js 函数

在JavaScript中,一个函数可以作为另一个函数的参数。我们可以先定义一个函数,然后传递,也可以在传递参数的地方直接定义函数。

const say = function(value) {
	console.log(value);
}
// someFunc参数是一个方法
function execute(someFunc,value) {
	someFunc(value);
}
execute(say,'ahri');

匿名函数

我们可以把一个函数作为变量传递。但是我们不一定要绕这个"先定义,再传递"的圈子,我们可以直接在另一个函数的括号中定义和传递这个函数:

function execute(someFunc,value) {
	someFunc(value);
}
execute(function(value) {
	console.log(value);
},'mikasa');

函数传递是如何让HTTP服务器工作的

来看看我们简约而不简单的HTTP服务器:

const http = require('http');
http.createServer(function(request,response) {
	response.writeHead(200, {"Content-Type": "text/plain"});
	response.write('i love ahri forever');	// 向页面输出内容
	response.end();
}).listen(8081);

现在它看上去应该清晰了很多:我们向 createServer 函数传递了一个匿名函数。

用这样的代码也可以达到同样的目的:

const http = require('http');
const onRequest = function(request,response) {
	response.writeHead(200, {"Content-Type": "text/plain"});
	response.write('i love ahri forever');	// 向页面输出内容
	response.end();
}
http.createServer(onRequest).listen(8082);

Node.js 路由

我们要为路由提供请求的 URL 和其他需要的 GET 及 POST 参数,随后路由需要根据这些数据来执行相应的代码。

因此,我们需要查看 HTTP 请求,从中提取出请求的 URL 以及 GET/POST 参数。这一功能应当属于路由还是服务器(甚至作为一个模块自身的功能)确实值得探讨,但这里暂定其为我们的HTTP服务器的功能。

我们需要的所有数据都会包含在 request 对象中,该对象作为 onRequest() 回调函数的第一个参数传递。但是为了解析这些数据,我们需要额外的 Node.JS 模块,它们分别是 url 和 querystring 模块。

                   url.parse(string).query
                                           |
           url.parse(string).pathname      |
                       |                   |
                       |                   |
                     ------ -------------------
http://localhost:8888/start?foo=bar&hello=world
                                ---       -----
                                 |          |
                                 |          |
              querystring.parse(queryString)["foo"]    |
                                            |
                         querystring.parse(queryString)["hello"]

当然我们也可以用 querystring 模块来解析 POST 请求体中的参数,稍后会有演示。

现在我们来给 onRequest() 函数加上一些逻辑,用来找出浏览器请求的 URL 路径:

const http = require('http');
const url = require('url');

const start = function() {
	function onRequest(req,res) {
		let pathname = url.parse(req.url).pathname;
		console.log('Request pathname'+ pathname +'received');
		res.writeHead(200, {"Content-Type": "text/plain"});
		res.write('i love ahri forever');
		res.end();
	}
	http.createServer(onRequest).listen(8081);
	console.log('server start');
}
exports.start = start;

好了,我们的应用现在可以通过请求的 URL 路径来区别不同请求了–这使我们得以使用路由(还未完成)来将请求以 URL 路径为基准映射到处理程序上。

在我们所要构建的应用中,这意味着来自 /start 和 /upload 的请求可以使用不同的代码来处理。稍后我们将看到这些内容是如何整合到一起的。

现在我们可以来编写路由了,建立一个名为 router.js 的文件,添加以下内容:

function route(pathname) {
	console.log('about to route a request for '+pathname);
}
exports.route = route;

如你所见,这段代码什么也没干,不过对于现在来说这是应该的。在添加更多的逻辑以前,我们先来看看如何把路由和服务器整合起来。

首先,我们来扩展一下服务器的 start() 函数,以便将路由函数作为参数传递过去,server.js 文件代码如下:

const http = require('http');
const url = require('url');

const start = function(route) {
	function onRequest(req,res) {
		let pathname = url.parse(req.url).pathname;
		console.log('Request pathname'+ pathname +'received');
		
		route(pathname);	// 使用路由处理pathname
		
		res.writeHead(200, {"Content-Type": "text/plain"});
		res.write('i love ahri forever');
		res.end();
	}
	http.createServer(onRequest).listen(8081);
	console.log('server start');
}
exports.start = start;

同时,我们会相应扩展 index.js,使得路由函数可以被注入到服务器中:

const server = require('./server');
const router = require('./router');

server.start(router.route);

然后启动服务:node index.js,可以看到相应的输出信息:

> node index.js
server start
Request pathname/ahrireceived
about to route a request for /ahri
Request pathname/favicon.icoreceived
about to route a request for /favicon.ico

在这里插入图片描述

Node.js 全局对象

Javascript有一个全局对象window,而Node.js中的全局对象为global。都是可以直接访问而不需要包含的。

全局对象与全局变量

global 最根本的作用是作为全局变量的宿主。按照 ECMAScript 的定义,满足以下条 件的变量是全局变量:

  • 在最外层定义的变量;
  • 全局对象的属性;
  • 隐式定义的变量(未定义直接赋值的变量)。

当你定义一个全局变量时,这个变量同时也会成为全局对象的属性,反之亦然。需要注 意的是,在 Node.js 中你不可能在最外层定义变量,因为所有用户代码都是属于当前模块的, 而模块本身不是最外层上下文。

注意: 永远不要使用 var 定义变量以避免引入全局变量,因为全局变量会污染 命名空间,提高代码的耦合风险。

__filename

__filename 表示当前正在执行的脚本的文件名。它将输出文件所在位置的绝对路径,且和命令行参数所指定的文件名不一定相同。 如果在模块中,返回的值是模块文件的路径。

console.log(__filename);	// 输出当前文件所在的绝对路径

__dirname

__dirname 表示当前执行脚本所在的目录。

console.log(__dirname);

setTimeout(cb, ms)

setTimeout(cb, ms) 全局函数在指定的毫秒(ms)数后执行指定函数(cb)。:setTimeout() 只执行一次指定函数。返回一个代表定时器的句柄值。

function printAhri() {
	console.log('ahri');
}
setTimeout(printAhri,1000);

结果:1s后输出 ahri

clearTimeout(t)

clearTimeout( t ) 全局函数用于停止一个之前通过 setTimeout() 创建的定时器。 参数 t 是通过 setTimeout() 函数创建的定时器。

function printAhri() {
	console.log('ahri');
}
let t = setTimeout(printAhri,2000);
clearTimeout(t);

结果:清除了定时器,什么也不会输出。

setInterval(cb, ms)

setInterval(cb, ms) 全局函数在指定的毫秒(ms)数后执行指定函数(cb)。

返回一个代表定时器的句柄值。可以使用 clearInterval(t) 函数来清除定时器。

setInterval() 方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。

let count = 0;
let t = setInterval(increame,100);	// 设置定时器
function increame() {
	count++;
	console.log(count);
	if(count>=5) {	// 设置定时器退出条件
		clearInterval(t);
	}
}

输出结果:

> node main.js
1
2
3
4
5

console

console 用于提供控制台标准输出,它是由 Internet Explorer 的 JScript 引擎提供的调试工具,后来逐渐成为浏览器的实施标准。

Node.js 沿用了这个标准,提供与习惯行为一致的 console 对象,用于向标准输出流(stdout)或标准错误流(stderr)输出字符。

process

process 是一个全局变量,即 global 对象的属性。

它用于描述当前Node.js 进程状态的对象,提供了一个与操作系统的简单接口。通常在你写本地命令行程序的时候,少不了要 和它打交道。下面将会介绍 process 对象的一些最常用的成员方法。

Node.js 常用工具

util 是一个Node.js 核心模块,提供常用函数的集合,用于弥补核心JavaScript 的功能 过于精简的不足。

util.inherits

util.inherits(constructor, superConstructor) 是一个实现对象间原型继承的函数。
JavaScript 的面向对象特性是基于原型的,与常见的基于类的不同。JavaScript 没有提供对象继承的语言级别特性,而是通过原型复制来实现的。

const util = require('util');
function Base() {
	this.name = 'ahri';
	this.base = '2019';
	this.sayHello = function() {
		console.log('Hello' + this.name);
	}
}
Base.prototype.showName = function() {
	console.log(this.name);
}
function Sub() {
	this.name = 'mikasa';
}
util.inherits(Sub,Base);
let objBase = new Base();
objBase.sayHello();
objBase.showName();
console.log(objBase);
let objSub = new Sub();
// objSub.sayHello();
objSub.showName();
console.log(objSub);

输出结果:

> node util.js
Helloahri
ahri
Base { name: 'ahri', base: '2019', sayHello: [Function] }
mikasa
Sub { name: 'mikasa' }

注意:Sub 仅仅继承了Base 在原型中定义的函数,而构造函数内部创造的 base 属 性和 sayHello 函数都没有被 Sub 继承。

同时,在原型中定义的属性不会被 console.log 作 为对象的属性输出。如果我们去掉 objSub.sayHello(); 这行的注释,将会看到:

C:\Users\Documents\HBuilderProjects\my_node\js\util\util.js:21
objSub.sayHello();
       ^

TypeError: objSub.sayHello is not a function
    at Object.<anonymous> (C:\Users\Documents\HBuilderProjects\my_node\js\util\util.js:21:8)
    at Module._compile (internal/modules/cjs/loader.js:701:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
    at Module.load (internal/modules/cjs/loader.js:600:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
    at Function.Module._load (internal/modules/cjs/loader.js:531:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:754:12)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)

util.inspect

util.inspect(object,[showHidden],[depth],[colors]) 是一个将任意对象转换 为字符串的方法,通常用于调试和错误输出。它至少接受一个参数 object,即要转换的对象。

showHidden 是一个可选参数,如果值为 true,将会输出更多隐藏信息。

depth 表示最大递归的层数,如果对象很复杂,你可以指定层数以控制输出信息的多 少。如果不指定depth,默认会递归2层,指定为 null 表示将不限递归层数完整遍历对象。

如果color 值为 true,输出格式将会以ANSI 颜色编码,通常用于在终端显示更漂亮 的效果。

特别要指出的是,util.inspect 并不会简单地直接把对象转换为字符串,即使该对 象定义了 toString 方法也不会调用。

const util = require('util');
function Person() {
	this.name = 'ahri';
	this.toString = function() {
		return this.name;
	}
}
let obj = new Person();
console.log(util.inspect(obj));
console.log(util.inspect(obj,true));

输出结果:

> node util.js
Person { name: 'ahri', toString: [Function] }
Person {
  name: 'ahri',
  toString:
   { [Function]
     [length]: 0,
     [name]: '',
     [arguments]: null,
     [caller]: null,
     [prototype]: { [constructor]: [Circular] } } }

util.isArray(object)

如果给定的参数 “object” 是一个数组返回true,否则返回false。

const util = require('util');
console.log(util.isArray([]));	// true
console.log(util.isArray(new Array()));	// true
console.log(util.isArray({}));	// false
console.log(util.isArray(null));	// false

util.isRegExp(object)

如果给定的参数 “object” 是一个正则表达式返回true,否则返回false。

const util = require('util');
console.log(util.isRegExp(/ahri/));	// true
console.log(util.isRegExp(new RegExp('ahri'))); 	// true
console.log(util.isRegExp({}));	// false

util.isDate(object)

如果给定的参数 “object” 是一个日期返回true,否则返回false。

const util = require('util');
console.log(util.isDate(new Date()));		// true
console.log(util.isDate(Date()));		// false	(without 'new' returns a String)
console.log(util.isDate('2019-07-07'));	// false

util.isError(object)

如果给定的参数 “object” 是一个错误对象返回true,否则返回false。

const util = require('util');
console.log(util.isError(new Error()));		// true
console.log(util.isError(new TypeError()));		// true
console.log(util.isError({name: 'Error',message: 'There is an error occurred'}));		// false
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值