node.js的基本学习(一)——环境配置与基本语法

前言:

今天我们开始nodejs的基本学习,Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。 Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。Node.js 的包管理器 npm,是全球最大的开源库生态系统。

 

 

 

 

 


环境配置:

首先我们配置nodejs的环境,打开官网

选择一个安装包下载即可

然后一直点下一步,傻瓜操作,就可以安装成功了

它会自动配置环境路径,我们可以在cmd下验证是否安装成功

然后我们去安装一个很出名的编辑器——VS code

 

它和VS是两码事,都是微软公司的产品,但是用法是不一样:

1、vs:Visual Studio是一个集成的开发环境,相对来说比较完整,它包括了整个软件生命周期中所需要的大部分工具,如UML工具、代码管控工具、集成开发环境(IDE)等等。

如果初学编程(控制台)用vs,cocos2dx开发游戏也是用vs。

2、vs code:是一款免费开源的现代化轻量级代码编辑器,支持几乎所有主流的开发语言的语法高亮、智能代码补全、自定义热键、括号匹配、代码片段、代码对比 Diff、GIT 等特性,支持插件扩展,并针对网页开发和云端应用开发做了优化。

 

在官网就可以安装VSnode,然后跟着这个网站实现汉化

然后我们在vsCode里安装一个插件——Terminal

它可以打开一个终端,可以方便我们查看命令的效果

基本环境就OK了,老规矩,学习一门新语言,先 hello world 一下

console.log("Hello World!");

Terminal输出:
PS F:\nodeJS的平时作品\helloNode> node app.js
Hello World!

 

 


基本语法:

全局对象:

JavaScript 中有一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问,即全局变量。

在浏览器 JavaScript 中,通常 window 是全局对象, 而 Node.js 中的全局对象是 global,所有全局变量(除了 global 本身以外)都是 global 对象的属性。

在 Node.js 我们可以直接访问到 global 的属性,而不需要在应用中包含它。

例如上面示例的console就是一个全局对象

再比如:

setTimeout(cb, ms) 全局函数在指定的毫秒(ms)数后执行指定函数(cb)。:setTimeout() 只执行一次指定函数。

返回一个代表定时器的句柄值。

setTimeout(()=>{
    console.log("请等三秒");
},3000)

三秒后输出了“请等三秒”

箭头函数=>是ES6语法,正常写法是这样

setTimeout(function(){
    console.log("请等三秒");
},3000);

另外还有例如:

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

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

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

setInterval(function(){
    console.log("每秒重复输出我");
},1000);
结果就会每秒都重复输出,按下Ctrl+C停止

还可以尝试一个

clearInterval
var time=0;
var timer=setInterval(function(){
    time+=2;
    console.log(time+"秒已经过去")
    if(time>5)
    {
        clearInterval(timer);
    }
},2000);
输出“2、4、6秒已经过去”后就不再输出了

全局对象更多内容可以查看这里

 函数表达式:

普遍函数定义:

函数定义非常简单:

function hashBlog(){
    console.log('is-hash.com');
}
hashBlog();
输出:is-hash.com

函数表达式:

变量保存对函数的引用

var hashBlog=function(){   //匿名函数
    console.log('is-hash.com'); 
} 
hashBlog();
输出:is-hash.com

回调函数:

回调函数概念:

1、回调函数是作为参数传递给另一个函数

2、回调函数是一段可执行的代码段,它作为一个参数传递给其他的代码,其作用是在需要的时候方便调用这段(回调函数)代码

3、 函数运行完成,再执行回调函数

回调函数特点:

1、不会立刻执行
回调函数作为参数传递给一个函数的时候,传递的只是函数的定义并不会立即执行。

2、是个闭包
回调函数是一个闭包,也就是说它能访问到其外层定义的变量。

3、执行前类型判断
在执行回调函数前最好确认其是一个函数。

function callFunction(fun){
    fun();
}
var hashBlog=function(){  //匿名函数
    console.log('is-hash.com');
}
callFunction(hashBlog);
输出:is-hash.com

加参数:

function callFunction(fun,who){
    fun(who);
}
var hashBlog=function(who){  //匿名函数
    console.log('is-hash.com'+who);
}
callFunction(hashBlog,"网站");
输出:is-hash.com网站

模块:

为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统。

模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个 Node.js 文件就是一个模块,这个文件可能是JavaScript 代码、JSON 或者编译过的C/C++ 扩展。

Node.js 提供了 exports 和 require 两个对象,其中 exports 是模块公开的接口require 用于从外部获取一个模块的接口,即所获取模块的 exports 对象。

示例:

我们新建两个文件

#main.js
var counter=function(arr){
    return "这里有一个长度为"+arr.length+"的数组"
}
module.exports=counter;


#app.js
var counter=require('./main.js');
console.log(counter(['superman','woderwoman','batman']));

然后node app,就会输出:这里有一个长度为3的数组

exports暴露多个属性,即暴露一个对象有多个建

#main.js
var counter=function(arr){
    return "这里有一个长度为"+arr.length+"的数组"
}

//return后面是`符号引注字符串,不是单引号
//这时一个ES6的模板字符串写法
//直接就是a+b的结果
var adder=function(a,b){
    return `两个数字相加之和为 ${a+b}`;
}

var PI=3.14;

//暴露的是一个对象
//对象有三个键(对用右边三个值)
module.exports.counter=counter;
module.exports.adder=adder;
module.exports.PI=PI;


#app.js
//接收一个对象
var stuff=require('./main.js');
console.log(stuff.counter(['superman','woderwoman','batman']));
console.log(stuff.adder(5,7));
console.log(stuff.PI);

这里有一个长度为3的数组
两个数字相加之和为 12
3.14

上面的main.js中可以直接简写export模块公开如下(更是有键值对应的感觉了)

module.exports={
        counter:counter,
        adder:adder,
        PI:PI
}

也可以直接用匿名函数作为值,这里就不写了

事件:

大多数 Node.js 核心 API 构建于惯用的异步事件驱动架构,其中某些类型的对象(又称触发器,Emitter)会触发命名事件来调用函数(又称监听器,Listener)。

例如,net.Server 会在每次有新连接时触发事件,fs.ReadStream 会在打开文件时触发事件,stream会在数据可读时触发事件。

所有能触发事件的对象都是 EventEmitter 类的实例。 这些对象有一个 eventEmitter.on() 函数,用于将一个或多个函数绑定到命名事件上。 事件的命名通常是驼峰式的字符串,但也可以使用任何有效的 JavaScript 属性键。。

当 EventEmitter 对象触发一个事件时,所有绑定在该事件上的函数都会被同步地调用。 被调用的监听器返回的任何值都将会被忽略并丢弃。

示例:

//events是一个核心库
var events=require('events');
//新增一个EventEmitter实例(EventEmitter是个类)
var myEmitter=new events.EventEmitter();

//EventEmitter实例绑定了一个事件
//名称是someEvent,发生之后调用后面那个回调函数
myEmitter.on('someEvent',function(message){
    console.log(message);
})
//用emit触发事件,传入后面为参数
//绑定在该事件上的所有函数会被同步调用
myEmitter.emit('someEvent','事件被触发');

输出:事件被触发

我们再来看一个大例子:

var events=require('events');
//导入util核心库
//util是一个工具库
var util=require('util');

//javascript中定义类的写法
var Person=function(name){
    this.name=name;
}
//该方法表明继承关系,让person继承EventEmitter
util.inherits(Person,events.EventEmitter);

//实例三个对象
var xiaoming=new Person('xiaoming');
var lili=new Person('lili');
var lucy=new Person('lucy');

var person=[xiaoming,lili,lucy];

person.forEach(function(person){
    person.on('speak',function(message){
        console.log(person.name+'said:'+message);
    })
})

xiaoming.emit('speak','我是小明');
lucy.emit('speak','我是路西');

输出:
xiaomingsaid:我是小明
lucysaid:我是路西

读写文件:

同步读取文件:

#test.txt
这里是text.txt,是一个用于测试的文本文件


#main.js
//导入核心库(文件系统)
var fs=require('fs');

//读取文件内容
//同步读取函数readFileSync,utf8:编码集
var test=fs.readFileSync("test.txt","utf8");
console.log(test);


输出:
这里是text.txt,是一个用于测试的文本文件

同步写入文件:

#main.js
//导入核心库(文件系统)
var fs=require('fs');

//同步写入函数writeFileSync,
var test=fs.writeFileSync("test.txt","这是第二个测试文件");

#test.txt
原本的内容改变成了:
这是第二个测试文件

同步操作(sync)会将命令从上到下依次执行,如果有阻塞就会一直卡到那一步(nodejs在执行javascripts的时候是单线程的)

 

异步读取文件:

#test.txt
这里是text.txt,是一个用于测试的文本文件

#main.js
//导入核心库(文件系统) 
var fs=require('fs'); 

//读取文件内容 
//异步读取函数readFile,utf8:编码集 
//后面是一个回调函数,err是错误信息,data就是test的文件内容
var test=fs.readFile("test.txt","utf8",function(err,data){
    if(err){
		console.log(err);
	}else{
		console.log(data);
	}
}); 
console.log("我是最后一句命令");


输出:
我是最后一句命令
这里是text.txt,是一个用于测试的文本文件

可以看到,“最后一句命令”尽然先输出了,这就是一个异步读取文件

内部操作:

nodejs维护了一个事件队列,首先执行var fs=require(‘fs’),然后执行第二条命令var test=fs.readFile(……)的时候,会注册一个事件,告诉这个事件队列它将要去读一个文件(但是此时没有执行后面的回调函数),然后在执行主线程的第三个语句console.log(“我是最后一句命令”),当主线程控线之后,他就会去找事件队列里的事件,把它取出来,再从线程池中发起一个线程,去执行这事件队列里面的事件,执行成功之后,它再告诉主线程它已经成功了,主线程再把数据取出。

这就是nodejs高性能的原因,它每一个方法是异步的

异步写入文件:

#main.js
//导入核心库(文件系统) 
var fs=require('fs'); 

//异步写文件
fs.writeFile('test.txt', '异步写入文件', function(err){
    if(err)
        console.log(err);
    else 
        console.log('写文件操作成功');
})

console.log("我是最后一句命令");


#test.txt
异步写入文件

创建和删除目录:

异步删除文件:

#main.js
//导入核心库(文件系统) 
var fs=require('fs'); 

fs.unlink("test.txt",function(){
    console.log("已经删除文件");
})

同步删除文件:

#main.js
//导入核心库(文件系统) 
var fs=require('fs'); 

fs.unlinkSync("test.txt")

同步创建目录:

//导入核心库(文件系统) 
var fs=require('fs'); 

fs.mkdirSync('DIR');

同步删除目录:

//导入核心库(文件系统) 
var fs=require('fs'); 

fs.rmdirSync('DIR');

fs的rmdir或者rmdirSync方法只能对空文件夹

异步创建目录:

//导入核心库(文件系统) 
var fs=require('fs'); 
fs.mkdir('DIR',function(err){
    if(err){
        console.log(err);
        return false;
    }
    console.log('创建目录成功');
})
创建了DIR目录

新建目录且新建文件示例:

//导入核心库(文件系统) 
var fs=require('fs'); 
fs.mkdir('DIR',function(err){
    if(err){
        console.log(err);
    }
    else{
        console.log('创建目录成功');
        fs.writeFile('./DIR/test.txt','异步文件',function(err){
            if(err){
                console.log(err);
            }
            else{
                console.log("创建文件成功");
            }
        })
    }
})

流和管道:

流:

流(stream)是 Node.js 中处理流式数据的抽象接口。 stream 模块用于构建实现了流接口的对象。

Node.js 提供了多种流对象。 例如,HTTP 服务器的请求和 process.stdout 都是流的实例。

流可以是可读的、可写的、或者可读可写的。 所有的流都是 EventEmitter 的实例。

流的应用:

  1. 处理数据,最典型的就是http服务的时候.请求和响应就是流的一种体现,再比如对数据进行的处理,例如webpack,gulp也大量运用了流这个技术,或者对文件进行打包压缩
  2. 提高读写性能,与文件系统的读写命令有所区别,文件系统的读写文件命令是一次性把文件里的内容放到内存当中,如果文件很大,用这种命令就不太合适,要用流来处理,流会把内容放到buffer(缓存)中,一边放一边处理,这样的话性能就会很高

示例:

#test.txt
在故事开始时,王后坐在……


#main.js
//导入核心库(文件系统) 
var fs=require('fs'); 

//__dirname是一个全局变量,代表当前目录
//createReadStream表示创建一个读的流(输入流)
var ReadStream=fs.createReadStream(__dirname+'/test.txt','utf8');
var data=""
//流是一个事件的示例,具有一些事件的特性
//例如绑定监听函数
//data事件是当有数据可读时触发
ReadStream.on('data',function(chunk){
    data+=chunk;
})
//end事件是接收数据完成之后触发
ReadStream.on('end',function(){
    console.log(data)
})


输出
在故事开始时,王后坐在……
ReadStream.setEncoding('utf8')//编码也可以这样写

而创建写入流写入内容也很简单:

//导入核心库(文件系统) 
var fs=require('fs'); 

//__dirname是一个全局变量,代表当前目录
//createWriteStream创建一个写的流(输出流)
var WriteStream=fs.createWriteStream(__dirname+'/test2.txt')
//编辑流出内容
var WriteData="小女孩穿着红舞鞋跳舞跳了一天!";
//流出
WriteStream.write(WriteData);
WriteStream.end();
//结束的监听方法
WriteStream.on('finish',function(){
    console.log('创建成功');
})

管道:

var myReadStream = fs.createReadStream(__dirname + '/readMe.txt')
var myWriteStream = fs.createWriteStream(__dirname+'/writeMe2.txt')
myReadStream.pipe(myWriteStream)

利用管道,直接复制出一个新文件

 

 

 

 


nodejs的第一部分就先记录到这里,有新的知识我会不断补充。

 

 

 

 

 

 

 

 

商业转载 请联系作者获得授权,非商业转载 请标明出处,谢谢

 

 

发表评论