JavaScript在客户端与服务端实现的功能不同,区别具体如下:
在客户端,JavaScript需要依赖浏览器提供的JavaScript引擎解析执行,浏览器提供了对DOM的解析,客户端不仅要应用语法,而且要会操作DOM和BOM。
在服务器端,JavaScript不依赖浏览器,而是由特定的运行环境提供的JavaScript引擎解析执行,例如Node.js,只需应用语法,不需要操作DOM和BOM。
JavaScript包括ECMAScript,DOM,BOM三个部分,具体如下:
- ECMAScript是JavaScript的核心语法
- DOM是HTML和XML的应用程序接口,用于控制文档的内容和结构。
- BOM(浏览器对象模型)可以对浏览器窗口进行访问和操作。
# 1.Node.js的特点与优势
- 它是一个JavaScript运行环境,前后端语言一致。
- 依赖于Chrome v8引擎进行代码解析,这个引擎负责在非浏览器解析情况下解析代码
- 事件驱动(Event-Driven)
- 非阻塞I/O:服务器端会设计阻塞I/O的操作,Node.js使用事件回调的方式实现非阻塞I/O
- 轻量,可伸缩,适于实时数据交互应用
- 单进程,单线程:阻塞I/O一个线程只能处理一个任务,非阻塞I/O一个线程永远在处理任务,Node.js采用 单线程,利用事件驱动的异步编程模式,实现了非阻塞I/O。
# 2.第一个Node.js的web程序
命令行运行node demo.js
,demo.js如下,打开浏览器输入127.0.0.1:3000,输出hello world
//加载http模块
var http = require('http');
//创建http服务器
http.createServer(function(req,res){
//响应结束
res.end('hello world');
//监听网址127.0.0.1 端口号3000
}).listen(3000,'127.0.0.1');
# 3.REPL运行环境(Read-Eval-Print-Loop)
打开终端,输入node即可进入REPL运行环境,可以解析JS代码,执行变量和函数的相关操作。
其实Chrome中的Console控制台就是REPL环境。
# 4.global对象和模块作用域
在Node.js中,默认声明的变量,函数都是属于当前文件模块,都是私有的,只有在当前模块作用域内可以使用,如果想在全局范围内为某个变量赋值,可以应用 全局对象global.
var foo = 'bar';
global.foo = foo;
console.log('global:foo'+global.foo);
# 4.1 require(),exports,module.exports
在一个文件模块中直接给某个全局变量赋值,显得很突兀,可能会污染命名空间,造成耦合的问题,为了解决上述问题,exports是模块公开的接口,require()用于从外部获取一个模块的接口。
info.js:
//向外开放变量name
exports.name = 'itcast';
//向外开放变量age
module.exports.age = '10';
//向外开放函数
module.exports.sayHello = function(){
console.log('hello');
}
demo.js
//加载模块
let myModule = require('./info');
console.log(myModule);
//输出模块中的变量值
console.log('name:'+myModule.name);
console.log('age:'+myModule.age);
//调用模块的方法
myModule.sayHello();
# 4.2 exports和module.exports的区别
exports是一个指向module.exports的引用,module.exports初始值为一个空对象{},所以exports初始值也是{},虽然exports和module.exports都可以向模块外开放变量和函数,但是使用上,module.exports可以单独定义,返回数据类型,而exports只能返回一个object对象。
例如:
test.js
//定义一个数组
module.exports=['name','type','age'];
demo2-5.js
//加载模块
let myModule = require('./test');
console.log(myModule);
//输出数组长度
console.log('length:'+myModule.length);
//输出 结果
//[ 'name', 'type', 'age' ]
//length:3
修改test.js中的代码
exports=['name','type','age'];
//最后输出
//{}
//length:undefined
可见使用exports直接定义数据,会切断exports与module.exports的联系,出现了找不到值的情况。
# 5.全局可用变量,函数和对象
即不需要进行模块加载,可以直接使用的,例如require()函数。
# 5.1 _dirname和 _filename变量
- _dirname表示当前文件所在的目录
- _filename表示当前正在执行的脚本的文件名。(绝对路径)
console.log('文件的目录是:'+__dirname);
console.log('文件的绝对路径是:'+__filename);
//输出
//文件的目录是:C:\Users\Jin\Desktop\前端学习\Node.js\chapter 02
//文件的绝对路径是:C:\Users\Jin\Desktop\前端学习\Node.js\chapter 02\demo2-6.js
# 5.2 全局函数
- setTimeout(cb,ms):ms后执行cb
- clearTimeout()
- setInterval(cb,ms):每ms后执行cb
- clearInterval()
- setImmediate(cb):延迟调用cb函数,cb将在I/O事件回调之后,setTimeout和setInterval回调之前调用
- clearImmediate()
# 5.3 console对象
console是一个全局对象,除了console.log()函数外还提供了其他函数
- console.info
- console.error
- console.warn
- console.dir:用来对一个对象进行检查,以易于阅读和打印的格式显示
- console.time和console.timeEnd
- console.trace:当前执行代码在堆栈中的调用路径
- console.assert:判断某个表达式或变量是否为真(断言)
# 6 重写计算器模块
以add.js为例,定义加减乘除模块
module.exports = function(x,y){
return parseInt(x)+parseInt(y);
}
index.js:分别使用require加载4个功能模块,并使用exports向外开放这4个接口
module.exports = {
add:require('./add');
//sub
//mul
//divide
}
testCal.js
var cal = require('./index');
console.log(cal.add(1,2));//3
# 7. require()的模块加载规则
主要分为两类:文件模块和核心模块
- 文件模块
require('路径.扩展名');
require('/example.js');//当前目录
require('./example.js');
require('../example.js');//上一目录
- 核心模块
核心模块包含了基本的API,保存在node.js源码的lib文件下,例如
- 全局对象
- 常用工具
- 事件机制
- 文件系统访问
- HTTP服务器与客户端
require('模块标识');
const os = require('os');
console.log(os.cpus());
# 8. 模块的缓存
多次使用同一模块,Node.js只会加载一次,模块被缓存在require.cache中
foo.js:
console.log('foo模块被加载了');
test.js:
require('./foo');
require('./foo');
require('./foo');
require('./foo');
//只输出一次 foo模块被加载了,说明只加载了一次
在foo.js加入
delete require.cache[module.filename];
//删除缓存后输出4次
模块化编程 →