Node.js概述及编程基础

Posted 遥岑.

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Node.js概述及编程基础相关的知识,希望对你有一定的参考价值。

Node.js概述

什么是Node.js

Node.js简称Node,是一个可以使javascript运行在服务器端的平台,是JavaScript的运行时环境,Node.js可以解析和执行JavaScript代码。
JavaScript本是一种Web前端语言,Node.js让JavaScript成为服务器端脚本语言,现在的JavaScript可以完全脱离浏览器来运行。
Node.js将V8引擎封装起来,作为服务器运行平台,以执行JavaScript编写的后端脚本程序。
Node.js进一步提升JavaScript的能力,在Node执行环境中提供了一些服务器级别的操作API,使JavaScript可以访问文件读取数据库访问进程,从而胜任后端任务。
Node.js是跨平台的。
Node.js除了自己的标准类库之外,还可使用大量的第三方模块系统来实现代码的分享和重用。
与其他后端脚本语言不同的是,Node.js内置了处理网络请求和响应的函数库,也就是自备了HTTP服务器,所以不需要额外部署HTTP服务器。
npm是世界上最大的开源库生态系统,绝大多数JavaScript相关的包都存放在了npm上,可以方便的下载使用。

Node的特点

  • 非阻塞I/O
    非阻塞I/O又称为异步式I/O。
    是指当线程遇到I/O操作时,不会以阻塞方式等待I/O操作完成或数据返回,而只是将I/O请求转发给操作系统,继续执行下一条指令。

阻塞I/O是指在执行过程中遇到I/O操作时,操作系统会撤销该线程的CPU控制权,使其暂停执行,处于等待状态,同时将资源转让给其他线程

  • 事件驱动
    非阻塞I/O是一种异步方式的I/O,与事件驱动密不可分。
    事件驱动以事件为中心,Node.js将每一个任务都当成事件处理。Node.js在执行过程中会维护一个事件队列,需执行的每个任务都会加入事件队列并提供一个包含处理结果的回调函数。
    在事件驱动模型中,会生成一个事件循环线程来监听事件,不断地检查是否有未处理的事件。
    Node.js的异步机制是基于事件的,所有磁盘I/O、网络通信、数据库查询事件都以非阻塞的方式请求,返回的结果由事件循环线程来处理。

JavaScript是一门单线程的语言,它的异步和多线程的实现是通过事件循环机制实现的

  • 单线程
    Node.js的应用程序是单线程的,但是通过事件回调支持并发,性能变得非常高。
    在阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须使用多线程。
    在非阻塞模式下,线程不会被I/O操作阻塞,该线程所使用的CPU核心利用率永远是100%,I/O操作以事件的方式通知操作系统。
    Node.js在主线程中维护一个事件队列,当接受请求后,就将该请求作为一个事件放入该队列,然后继续接收其他请求。
    Node.js内部通过线程池来完成非阻塞I/O,Node.js的单线程是指对JavaScript层面的任务处理是单线程的,而Node.js本身是一个多线程平台。

Node程序的运行方式

  • 使用npm包管理器
//在package.json文件中配置启动(start):
"scripts": {
	 "start": "node ./src/server.js",
	 "test": "echo \\"Error: no test specified\\" && exit 1"
}
			  
//用npm启动start
	  npm start
  • Node程序文件名

Node.js编程基础

Node.js自6.0版本开始全面支持ES6。

JavaScript语句与注释

  • 每条语句都以“ ; ”结束
  • 一行可以有多条语句(若一行有多条语句,每条语句都要以“ ; ”结束,建议一行只有一条语句)
  • 若一行语句太长可以用“ \\ ”进行续行
  • 语句块:由多条语句组成,这些语句都在“ { } ”中
  • 注释:单行注释:“ // ” ;多行注释:“ /* … */ ”

在WebStorm中,单行注释的快捷键:Ctrl + ’ / ‘;多行注释的快捷键:Ctrl+Shift+’ / ’

变量

  • 可以是任意的数据类型
  • 变量名是由字母、数字、下划线“ _ ”、“ $ ”组成的字符序列,但是首字符不能是数字
  • JavaScript是弱类型语言,在定义变量时不需要指定变量的类型,都可以使用关键字var声明
  • 可以在声明变量的同时赋值,也可以先声明变量然后再赋值
  • 变量可以反复的赋值

变量的提升和泄露

变量提升

在ES5中变量可以在声明之前使用,它的值是undefined。
ES6中使用let关键字声明变量来改变这种行为,变量不能在声明之前使用。

console.log(test);  //变量提升 结果为undefined
var test = 'hi';

变量泄露

在语句块中使用var关键字声明的变量,会被提升为全局变量,这样就会造成局部变量值的泄漏。
防止变量值的泄漏方法是使用let关键字声明局部变量。

var temp = 'Hello';
for(var i=0;i<temp.length;i++)
{
     console.log(temp[i]);
}
console.log(i);  //用var声明i 提升为全局变量 i=6 变量泄露

全局作用域和函数作用域

ES5中作用域只有两个:

  1. 全局作用域:从声明的位置开始到源程序的结束均有效
  2. 函数作用域:只在函数范围内有效

ES6中增加的块级作用域:在ES6中使用let关键字声明的变量只在它所在的块级作用域中有效。

常量

ES6中使用const关键字定义只读常量。

数据类型

Number(数值类型)

  • 不区分整数和浮点数
  • 二进制以0b开头,八进制数以0o开头,十六进制以0x开头
  • 若不能计算出结果显示为NaN(Not a Number),Infinity表示无限大

String(字符串)

  • 使用单引号或双引号括起来的文本(字符序列)
  • ES6提供模板字符串:反引号将模板字符串括起来,用 ${ }变量括起来
var host = `http://localhost`;
var port = 8080;
var url = `API接口为:${host}:${port}` //模板字符串
console.log(url) //输出: API接口为:http://localhost:8080
  • 模板字符串中可以不嵌入任何变量,按实际格式输出

Boolean(布尔类型)

  • 值只有true、false两种,常用于条件判断

在比较等于时,建议使用 === 而不是 ==

null 和 undefined

  • null:表示空值,即什么也没有
  • undefined:表示’未定义’,通常用于判断函数的参数是否正常传递

Array(数组)

  • 数组用[ ]表示,元素之间用逗号分隔
  • 数组元素可以是任意类型
  • 通过数组名带索引访问数组元素,索引的范围是 0~数组长度减1

Object(对象)

  • 用’ { } '表示,是由键值对组成的无序集合,键值对之间用逗号分隔,'键’就是对象的属性
  • 键的类型必须是字符串类型,值可以是任意类型
  • 通过’对象名.属性名(键名)'来访问对象的属性
  • ES6中允许将表达式作为键名,但表达式必须放在’[ ]'中

Symbol(符号)
ES6引入的新类型,用来表示一个独一无二的值,其值通过Symbol( )函数自动生成。
Symbol值可以作为对象的属性名。

有三种表示方式:

let k = Symbol(); 
let obj = {}

//第一种
obj[k] = "hi"
console.log(obj)

//第二种
let myobj = {
    [k]:"hi"
}
console.log(myobj)

//第三种
let obj2 = {}
Object.defineProperty(obj2,k,{value:'hello'})
console.log(obj2[k])

Set(集合)
集合是无重复的无序的数据结构,类似于数组,集合中的成员不重复,都是唯一的。
集合是一个构造函数,用于生成Set数据结构。

  • Set函数可以接收一个数组作为参数
var arr = [5,2,7,5,2,5,8];
const s1 = new Set(arr);
console.log(s1); //输出: Set{5,2,7,8}
  • 属性:
    constructor:表示构造函数
    size:表示集合的元素个数
var arr = [5,2,7,5,2,5,8];
const s1 = new Set(arr);
console.log(Set.prototype.constructor); //输出:[Function:Set]
console.log(s1.size); //输出:4
  • 方法(函数):
    add(x):将x添加到集合中
    delete(x):删除集合中的x,返回的是布尔值
    has(x):返回布尔值,表示x是否是集合的成员
    clear():清除所有成员,没有返回值
var s1 = new Set([45,23,78,44,56])
console.log(s1)
console.log(s1.keys()) //通过迭代器(遍历器)来遍历集合中的元素
console.log(s1.values()) //Set集合没有键只有值 keys遍历和values遍历结果是一样的
console.log(s1.entries()) //遍历键值对

遍历的使用:

  • […集合名]
var s2 = new Set(['red','blue','green'])
let arr = [...s2] //遍历集合 将集合元素赋给一个数组 ...不定参数
console.log(arr)
  • map遍历
set = new Set([...set].map(x => x*2)) //通过map遍历集合中的元素,让每个元素乘以2
  • filter过滤集合元素
let set = new Set([1,2,3,4,5,6,7,8,9]);
set = new Set([...set].filter(x => (x%2)==0)); //遍历set集合,并将集合中的偶数全部过滤出来
//输出:2,4,6,8

Map(映射)
ES6引入Map数据结构,与对象类似,但各种类型的数据都可以作为键
Map本身是一个构造函数,用于生成Map数据结构。

//set方法给map设置一个键值对
let map2 = new Map()
map2.set('school','11')
console.log(map2)
//get 获取键对应的值
console.log(map2.get('school'))
console.log(map2.keys()) //获取键
console.log(map2.values())
  • 可以使用Map结构的set方法添加成员
  • 使用Map结构的get方法读取键(成员)

WeakSet集合

集合中的元素只能是对象,不能是其他类型。
Node的垃圾回收机制,不考虑WeakSet中元素的回收。

   let ws = new WeakSet({"name":"张三"})

数组或集合的遍历

ES5:

  • ES5中使用的方式
 for(var i=0;i<array.length;i++)
 {
 	console.log(array[i])
 }
  • forEach循环
 array.forEach(x => console.log(x))
  • for( 变量 of 数组名或集合名)
 for(let k of array){
	console.log(k)
}

函数

函数的声明

function 函数名([参数]){
	 函数体语句;
}

 //ES6支持默认参数的函数
function testFun(x=21,y=19){
	 return x+y
}

函数的调用

 //事件名 = 函数名([参数])
 testFun(45,78)

默认参数的函数

//默认参数的函数
function testArgs(x=21,y=19) {
    //x,y参数带有默认值
    return x+y;
}

//调用函数
let s1 = testArgs();
console.log(s1);
//40

//传参
let s2 = testArgs(78,56);
console.log(s2);
//134

//传一个参数
let s3 = testArgs(20);
console.log(s3);
//39

ES6中的rest参数

JacaScript的函数默认带有arguments对象,利用该对象可以获得调用者传入的所有参数。

//我们在定义函数时 函数默认自带一个argument对象 对象中存放函数的所有参数
function testSum() {
    let sum = 0;
    for(let i=0;i<arguments.length;i++)
    {
        sum = sum + arguments[i];
    }
    return sum;
}

//无参的调用
console.log(testSum())
//有参调用
console.log(testSum(1,2,3))

ES6中的rest参数(…变量名),用于获取函数的多于参数,可以替代ES5中的arguments对象。

//es6中rest参数
function test(...values) {
    let sum = 0;
    for(let k of values)
    {
        sum += k;
    }
    return sum;
}
console.log(test(2,4,6))

匿名函数
在声明函数时省略函数名。

//匿名函数
var test = function (x,y) {
    return x+y;
}
let s = test(78,89)
console.log(s)

箭头函数
使用箭头符号(=>)声明的函数。

var 变量名 = ([参数])=> {
	函数体语句;
}
  • 若函数体语句只有一条,可以省略’{ }’

高阶函数
把函数作为参数的函数。

 //高阶函数:把abs函数作为参数
	function  diffAvg(m,n,fn){
		return fn(m-n);
}

//高阶函数的调用:
let k = diffAvg(45,78,Math.abs)

console.log("高阶函数:"+k);
  • fn:函数指针,指向的实参函数的入口地址(函数名代表了函数的入口地址)

闭包

当函数作为返回值或参数传递时,该函数就被称为闭包。
闭包是能够读取其他函数内部变量的函数,可以使用函数之外定义的变量。

//闭包:将函数作为返回值或参数 能够读取其他函数内部的变量
var basePrice = 10.00; //起步价
var baseMiles = 3.00;  //起步里程
function taxiPrice(unitPrice,Mileage) {
    function totalPrice() {  //计算总费用
        if(Mileage > baseMiles)
        {
            return Mileage*unitPrice;
        }
        else
        {
            return basePrice;
        }
    }
    return totalPrice(); //返回函数
}

console.log(taxiPrice(2,6));

ES5中通过函数来创建实例对象。

//ES5通过函数创建实例对象
function Visitor(vname,sex) { //是一个类名 也是一个函数名(构造函数)
    this.vname = vname;
    this.sex = sex;
}
Visitor.prototype.getInfo = function () { //通过原型对象添加函数
    return this.vname + this.sex;
}
//创建实例对象
var visitor = new Visitor('邓瑛','男');
console.log(visitor.getInfo())

ES6中引入类模板,使用class关键字定义类。

//ES6中类的定义
class Visitor {
    constructor(vname,sex) { //构造函数 初始化对象的属性
        this.vname = vname;
        this.sex = sex;
    }
    getInfo() {
        return this.vname + this.sex;
    }
}
var visitor = new Visitor('遥岑','女'); //通过类名调用了构造函数
console.log(visitor.getInfo());

代码规范

编码格式:

  • 每条JavaScript语句都以分号结束。建议每行只有一条语句
  • 缩进使用2个半角空格或4个半角空格, 而不使用Tab键
  • 每行仅声明一个变量,而不要声明多个变量
  • 字符串尽量使用单引号
  • 符号“{”应在行末,表示代码块的开始,符号“}”应在行首,表示代码块的结束

命名规范:

  • 变量名采用小驼峰命名法(除第一个单词之外,其他单词首字母大写)
  • 常量全部采用大写
  • 函数名也采用小驼峰命名法,第一个单词采用动词
  • 类和构造函数名采用大驼峰命名法(每个单词的首字母都是大写),第一个单词使用名词
  • 文件名采用下划线分割单词

以上是关于Node.js概述及编程基础的主要内容,如果未能解决你的问题,请参考以下文章

青训营Node.js基础 - 异步编程四种解决方案

2021了,真的不要再说 Node.js 是一门编程语言了

2021了,真的不要再说 Node.js 是一门编程语言了

2021了,真的不要再说 Node.js 是一门编程语言了

深入理解node.js异步编程:基础篇

Node.js 网络编程 (上)Web基础知识实现HTTP及GETPOST的创建