NodeJs基础三


10.Node.js函数
11.Node.js路由
12.Node.js全局对象
13.Node.js常用工具

十、Node.js函数

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

1
2
3
4
5
6
7
function say(word){
console.log(word);
}
function execute(someFunction, value){
someFunction(value);
}
execute(say, "hello"); // 把函数以参数的形式传递

我们把say函数作为execute函数的第一个变量进行了传递。这里返回的不是say的返回值,而是say本身!
这样一来,say就变成了execute中的本地变量someFunction,execute可以通过使用someFunction()来使用say函数。

1.匿名函数

我们可以直接在另一个函数的括号中定义和传递这个函数

1
2
3
4
function execute(someFunction, value){
someFunction(value);
}
execute(function(word){console.log(word)}, "hello"); // 使用匿名函数传参

我们在execute接受第一个参数的地方直接定义了我们准备传递给execute的匿名函数。

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

1
2
3
4
5
6
var http = require("http");
http.createServer(function(request, response){
response.writeHead(200, {"Content-Type":"text/plain"});
response.write("Hello World");
response.end();
}).listen(8888);

我们向createServer函数传递了一个匿名函数,效果与以下代码相同

1
2
3
4
5
6
7
var http = require("http");
function onRequest(request, response){
response.writeHead(200, {"Content-Type":"text/plain"};
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);


十一、Node.js路由

我们要为路由提供请求的URL其他需要的GET及POST参数,随后路由需要根据这些数据来执行相应的代码。
因此,我们需要查看HTTP请求,从中提取出请求的URL以及GET/POST参数。这些数据都会包含在request对象中,该对象作为onRequest()回调函数的第一个参数(request)传递。为了解析这些数据,我们需要额外的Node.js模块,它们分别是urlquerystring模块。

1
2
3
4
5
6
7
8
9
10
11
12
13
                   url.parse(string).query
|
url.parse(string).pathname |

| |
| |
------ -------------------
http://localhost:8888/start?foo=bar&hello=world
--- -----
| |
| |
querystring(string)["foo"] |
|

querystring(string)["hello"]

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var http = require("http");
var url = require("url");
function start(){
function onRequest(request, response){ // 请求的url及get/post参数都包含在request对象中
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
response.writeHead(200, {"Content-Type":"text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;

现在我们的应用可以通过请求的URL路径来区别不同请求了–这使我们得以使用路由来将请求以URL路径为基准映射到处理程序上
路由文件router.js:

1
2
3
4
function route(pathname){
cosole.log("About to route a request for " + pathname);
}
exports.route = route;

我们将使用依赖注入的方式较松散地添加路由模块。
首先,我们来扩展一下服务器的start()函数,以便将路由函数作为参数传递过去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var http = require("http");
var url = require("url");
function start(route){
function onRequest(request, response){
var pathname = url.parse(request.url).pathname;
console.log("Request for" + pathname + " received.");
route(pathname); //
response.writeHead(200, {"Content-Type":"text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started");
}
exports.start = start;

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

1
2
3
var server = require("./server");
var router = require("./router");
server.start(router.route);

现在启动应用,随后请求一个URL,将会看到应用输出相应的信息,这表明我们的HTTP服务器已经在使用路由模块了,并会将请求的路径传递给路由

1
2
3
node index.js
Request for /foo received.
About to route a request for /foo


十二、Node.js全局对象

JavaScript中有一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问,即全局变量
在浏览器JavaScript中,通常window是全局对象,而Node.js中的全局对象是global所有全局变量都是global对象的属性
在Node.js我们可以直接访问到global的属性,而不需要在应用中包含它。

1.全局对象和全局变量

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

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

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

2.__filename

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

1
2
3
4
5
// 创建main.js文件,输出全局变量__filename的值
console.log(__filename);
// 执行main.js文件
node main.js
/Desktop/nodejs/main.js

3.__dirname

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

1
2
3
4
5
// 创建main.js文件,输出全局变量__filename的值
console.log(__filename);
// 执行main.js文件
node main.js
/Desktop/nodejs

4.setTimeout(cb, ms)

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

1
2
3
4
5
function printHello(){
console.log("Hello, World!");
}
// 两秒后执行以上函数
setTimeout(printHello, 2000);

5.clearTimeout(t)

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

1
2
3
4
5
6
7
function printHello(){
console.log("Hello, World!");
}
// 设置两秒后执行定时器
var t = setTimeout(printHello, 2000);
// 清除定时器
clearTimeout(t);

6.setInterval(cb, ms)

setInterval(cb, ms)全局函数在指定毫秒数后执行指定函数。
返回一个代表定时器的句柄值。可以使用clearInterval(t)函数来清除定时器。

1
2
3
4
function printHello(){
console.log("Hello, World");
}
setInterval(printHello, 2000);

以上程序每隔两秒就会输出一次“Hello, World”。

7.console

console用于提供控制台标准输出,它是由Internet Explorer的JScript引擎提供的调试工具,后来逐渐成为浏览器的事实标准。
Node.js沿用了这个标准,提供与习惯行为一致的console对象,用于向标准输出流(stdout)或标准错误流(stderr)输出字符。

8.process(未完)

process是一个全局变量,即global对象的属性。
它用于描述当前Node.js进程状态的对象,提供了一个与操作系统的简单接口。
事件&描述
exit:当进程准备退出时触发
beforeExit:当node清空事件循环,并且没有其他安排时触发这个事件。
uncaughtException:当一个异常冒泡回到事件循环,触发这个事件。
Signal事件:当进程接收到信号时就触发。


十三、Node.js常用工具

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

1.util.inherits

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var util = require('util');
function Base(){
this.name = 'base';
this.base = 1991;
this.sayHello = function(){
console.log("Hello " + this.name);
}
}
Base.prototype.showName = function(){
console.log(this.name);
}
function Sub(){
this.name = 'sub';
}
util.inherits(Sub, Base);
var objBase = new Base();
objBase.showName(); // base
objBase.sayHello(); // Hello base
console.log(objBase); // { name:'base', base:1991, sayHello:[Function] }
var objSub = new Sub();
objSub.showName(); // sub,这里调用了Sub继承自Base的原型中的showName()函数
console.log(objSub); // { name:'sub' }

我们定义了一个基础对象Base和一个继承自Base的Sub,Base有三个构造函数内定义的属性和一个原型中定义的函数,通过util.inherit实现继承
PS:Sub仅仅继承了Base在原型中定义的showName()函数,而构造函数内部创造的base属性和sayHello函数都没有被Sub继承。同时,在原型中定义的属性不会被console.log作为对象的属性输出。

2.util.inspect

util.inspect:是一个将任意对象转换为字符串的方法,通常用于调试和错误输出。它至少接受一个参数object,即要转换的对象。
showHidden是一个可选参数,如果值为true,将会输出更多隐藏信息
depth表示最大递归的层数,如果对象很复杂,可指定层数以控制输出信息的多少。如果不指定depth,默认会递归2层,指定null表示将不限递归层数完整遍历对象。

1
2
3
4
5
6
7
8
9
var util = require('util');
function Person(){
this.name = 'byvoid';
this.toString = function(){
return this.name;
}
}
var obj = new Person();
console.log(util.inspect(obj));

3.util.isArray(object)

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

1
2
3
4
var util = require('util');
util.isArray([]) // true
util.isArray(new Array) // true
util.isArray({}) // false

4.util.isRegExp(object)

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

1
2
3
4
var util = require('util');
util.isRegExp(/some regexp/); // true
util.isRegExp(new RegExp('another regexp'));// true
util.isRegExp({}); // false

5.util.isDate(object)

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

1
2
3
4
var util = require('util');
util.isDate(new Date()); // true
util.isDate(Date()); // false
util.isDate({}) // false

6.util.isError(object)

1
2
3
4
var util = require('util');
util.isError(new Error()); // true
util.isError(new TypeError()); // true
util.isError({ name:'Error', message:'an error occurred' }) // false