Node.js入门

概念

Node.js虽然带一个js后缀,但它实际是采用谷歌chrome浏览器V8引擎,由C++语言编写的一个js运行环境。

node.js不是一门语言,不是库、不是框架,就是一个Javascript运行时环境。Node.js可以解析执行Javascript代码。

以前只有浏览器可以解析执行Javascript代码,现在的Javascript可以完全脱离浏览器运行,一切都归功于Node.js

浏览器中的Javascript:

EcmaScript

BOM

DOM

Node.js中的Javascript:

没有BOM/DOM

EcmaScript

提供了一些服务器级别的操作API,这些API绝大多数都被包裹到一个具名的核心模块中,例如文件操作的 fs 核心模块、http服务构建的 http 模块,路径操作的 path 模块、操作系统的 os 模块等。

版本常识

偶数位为稳定版本        -0.6.x  -8.x.x  LTS(long time support长期支持版)

奇数位为非稳定版本  -0.7.x  -9.x.x  Current(体验版,最新特性版)

建议安装稳定版本

安装

windows下

直接在nodejs官网下载并点击下一步下一步进行安装即可。

完成后打开命令行工具直接输入 node -v,如果能够输出版本号就说明安装成功了

Mac下

升级系统到最新

升级xcode(下面的是通过命令行安装):

  xcode-select -p(检查是否安装过,安装过会给返回一个路径地址,如果没有返回路径,接着执行下面的命令)

  xcode-select --install

安装Homebrew(专门针对Mac的套件管理器)

  打开brew官网https://brew.sh/,找到 Install Homebrew下面的命令复制到命令台回车。

brew install node回车

nodejs初体验

 起一个web服务器

打开nodejs官网,点击 about 选项,将第一段代码复制到一个server.js中。

const http = require('http');   //加载http模块,用来创建web服务器及处理http相关的任务等等

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {    //通过createServer方法创建服务器
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Hello World\n');
});

server.listen(port, hostname, () => {   //通过listen来监听服务器端口
    console.log(`Server running at http://${hostname}:${port}/`);
});

在sever.js文件处打开终端,在终端输入

node server.js

回车,即可看到终端输出

Server running at http://127.0.0.1:3000/

打开网址,可以看到是一个写着hello world的网页。

模块与包管理工具

Commonjs是一套规范。nodejs借鉴Commonjs并基于Commonjs的modules的管理规范实现了一套模块管理系统。在nodejs中,每一个文件都可以看做是一个单独的模块,在其中不需要有命名空间。不用担心变量污染。

在nodejs中,文件和模块是一一对应的。模块分为几种类型。大致可分为核心模块、用户自定义模块和通过npm安装的第三方模块。

Node中的模块系统

根据模块的类型,有几种引入模块的方式:在nodejs中,可以通过文件路径来引入模块,也可以通过模块名称来引用。如果用文件名引用非核心模块,node会最终将文件名映射到对应的文件的路径。

使用模块的流程:创建模块 => 导出模块(exports.xx) => 加载模块(require(XX)) => 使用模块。

示例:在一个学校,有班级,有老师和学生。将学校看做一个模块,将班级看做一个模块(class.js),将老师看做一个模块(teacher.js),将学生看做一个模块(student.js)。

先从student.js开始,写入代码:

function add(student) {
    console.log('Add student: ' + student);
}
//将add方法暴露出去
exports.add = add;

teacher.js文件

function add(teacher) {
    console.log('Add teacher: ' + teacher);
}
//将add方法暴露出去
exports.add = add;

class.js代码

var student = require('./student');
var teacher = require('./teacher');

teacher.add('teacher1');

function add(teacherName, studentNames) {
    teacher.add(teacherName);
    studentNames.forEach(function (studentName) {
        student.add(studentName);
    })
}

exports.add = add;

入口文件index.js

var classModule = require('./class');
classModule.add('teacher2', ['student1', 'student2']);

打开命令行,输入node index.js回车,就会输出我们添加的信息

主要 API总结

url(网址解析)

打开命令行,输入node进入node环境,输入url回车,会在命令行中打印出它的几个方法。

(1)parse

语法:url.parse(urlString[, parseQueryString[, slashesDenoteHost]])

  urlString:要解析的url字符串

  parseQueryString:布尔值,默认为false。如果设置为true,query属性将始终返回一个由querystring模块返回的一个对象。设置为false,则query属性将返回一个未解析的字符串。

  slashesDenoteHost:布尔值,默认为false。如果设置为true,在//之后和/之前的字符串将被解析成域名host。

在命令行中输入

url.parse('http://www.cnblogs.com/lianglanlan/p/8665777.html')

回车后,命令行会输出

Url {
  protocol: 'http:',        //底层使用的协议
  slashes: true,          //是否有双斜线
  auth: null,
  host: 'www.cnblogs.com',    //域名
  port: null,            //端口,默认为80
  hostname: 'www.cnblogs.com',  //主机名
  hash: null,            //锚点
  search: null,           //查询的字符串参数
  query: null,            //发送给服务器的数据
  pathname: '/lianglanlan/p/8665777.html',  //访问资源的路径名
  path: '/lianglanlan/p/8665777.html',     //路径
  href: 'http://www.cnblogs.com/lianglanlan/p/8665777.html' }

可以看到url.parse已经把这个地址解析为一个对象。

 对网址进行一下修改

url.parse('http://www.cnblogs.com:8080/lianglanlan/p/8665777.html?from=blog&author=lanlan#floor1')

回车后,命令行输出结果如下:

Url {
  protocol: 'http:',
  slashes: true,
  auth: null,
  host: 'www.cnblogs.com:8080',
  port: '8080',
  hostname: 'www.cnblogs.com',
  hash: '#floor1',
  search: '?from=blog&author=lanlan',
  query: 'from=blog&author=lanlan',
  pathname: '/lianglanlan/p/8665777.html',
  path: '/lianglanlan/p/8665777.html?from=blog&author=lanlan',
  href: 'http://www.cnblogs.com:8080/lianglanlan/p/8665777.html?from=blog&author=lanlan#floor1' }

将第二个参数设置为true,在命令行输入:

url.parse('http://www.cnblogs.com:8080/lianglanlan/p/8665777.html?from=blog&author=lanlan#floor1',true)

回车后命令行输出:

Url {
  protocol: 'http:',
  slashes: true,
  auth: null,
  host: 'www.cnblogs.com:8080',
  port: '8080',
  hostname: 'www.cnblogs.com',
  hash: '#floor1',
  search: '?from=blog&author=lanlan',
  query: { from: 'blog', author: 'lanlan' },
  pathname: '/lianglanlan/p/8665777.html',
  path: '/lianglanlan/p/8665777.html?from=blog&author=lanlan',
  href: 'http://www.cnblogs.com:8080/lianglanlan/p/8665777.html?from=blog&author=lanlan#floor1' }

可以看到query的属性值变成了对象。

第三个参数,设置为false时

> url.parse('//www.cnblogs.com:8080/lianglanlan/p/8665777.html',true)
Url {
  protocol: null,
  slashes: null,
  auth: null,
  host: null,
  port: null,
  hostname: null,
  hash: null,
  search: '',
  query: {},
  pathname: '//www.cnblogs.com:8080/lianglanlan/p/8665777.html',
  path: '//www.cnblogs.com:8080/lianglanlan/p/8665777.html',
  href: '//www.cnblogs.com:8080/lianglanlan/p/8665777.html' }

可以看到,在url没有协议http或https时,host是不能正确解析出来的。

将第三个参数设为true:

> url.parse('//www.cnblogs.com:8080/lianglanlan/p/8665777.html',true,true)
Url {
  protocol: null,
  slashes: true,
  auth: null,
  host: 'www.cnblogs.com:8080',
  port: '8080',
  hostname: 'www.cnblogs.com',
  hash: null,
  search: '',
  query: {},
  pathname: '/lianglanlan/p/8665777.html',
  path: '/lianglanlan/p/8665777.html',
  href: '//www.cnblogs.com:8080/lianglanlan/p/8665777.html' }

可以看到host与path和pathname属性都能正确的解析出来。

(2)format

与parse作用相反,将上面用parse方法生成的对象传入给format

> url.format({protocol: 'http:', slashes: true, auth: null, host: 'www.cnblogs.c
om:8080', port: '8080', hostname: 'www.cnblogs.com', hash: '#floor1', search: '?
from=blog&author=lanlan', query: 'from=blog&author=lanlan', pathname: '/lianglan
lan/p/8665777.html', path: '/lianglanlan/p/8665777.html?from=blog&author=lanlan'
, href: 'http://www.cnblogs.com:8080/lianglanlan/p/8665777.html?from=blog&author
=lanlan#floor1'})

回车后命令行输出

'http://www.cnblogs.com:8080/lianglanlan/p/8665777.html?from=blog&author=lanlan#floor1'

(3)resolve

进行url拼接处理

在命令行中输入

url.resolve('http://www.cnblogs.com/','/lanlan/p')

回车后,命令行输出

'http://www.cnblogs.com/lanlan/p'

QueryString

querystring模块用于解析或序列化请求参数的字符串。

(1)stringfy

序列化请求参数的字符串

语法:querystring.stringify(obj[, sep[, eq[, options]]])

  obj:对象。要序列化的参数对象。

  sep:字符串,默认为 & 。用于分隔查询字符串中的键值对的子字符串。

  eq:字符串,默认为 = 。用于分隔查询字符串中键和值的子字符串。

  options:对象,其中有encodeURIComponent方法。默认情况下需要编码为utf-8,如果需要替换编码,则需指定一个替代encideURIComponent选项。

示例:

//一个参数
> querystring.stringify({teacher:'teacher1',student:['student1','student2'],clas
s:1})
'teacher=teacher1&student=student1&student=student2&class=1'

//三个参数
> querystring.stringify({teacher:'teacher1',student:['student1','student2'],clas
s:1},';',':')
'teacher:teacher1;student:student1;student:student2;class:1'

(2)parse

将URL的querystring解析为键值对的组合(反序列化)。

语法:querystring.parse(str[, sep[, eq[, options]]])

参数与stringfy的相同。

>querystring.parse('teacher=teacher1&student=student1&student=student2&class=1')
{ teacher: 'teacher1',
  student: [ 'student1', 'student2' ],
  class: '1' }
>

(3)escape(转义)与unescape(反转义)

> querystring.escape('<哈哈>')
'%3C%E5%93%88%E5%93%88%3E'
> querystring.unescape('%3C%E5%93%88%E5%93%88%3E')
'<哈哈>'

http

HTTP具体概念参照:HTTP笔记

events

原文地址:https://www.cnblogs.com/lianglanlan/p/8665777.html