谈谈浏览器和nodejs环境区别
- nodejs环境上多了模块化
- 浏览器中的闭包、事件循环、作用域的区别?
模块化
- 在Node.js环境中,可以使用CommonJS或ES模块系统进行模块化
- 在nodejs中,每个文件都被视为一个模块
闭包
- 在Node.js环境中,闭包通常用于创建私有变量或实现模块化。
- 函数内部使用了外部的变量就会产生闭包
- 闭包产生的本质就是,当前环境中存在指向父级作用域的引用
- 在nodejs中,模块作用域中,如果一个函数引用了外部变量,那么这个函数就形成了一个闭包
- 因为它封装了对外部变量的访问,使得这个变量即使在函数执行完毕后,仍然不会被垃圾回收机制回收
- 在nodejs中,模块作用域可以形成闭包,使得函数可以访问模块内部的变量
- 在nodejs中,定义的变量,是模块私有变量
// nodejs的环境下产生了闭包, 浏览器中没有产生闭包
var i = 1; // nodejs中,定义了模块私有变量,在浏览器中,是全局变量
function a() {
console.log(i);
}
a();
作用域
-
在nodejs中,不仅有全局作用域,还有模块作用域
- 每个nodejs文件都是一个模块,都有自己的作用域,也就是模块作用域
- 在node.js中,每个模块都有自己的作用域,不会将变量泄漏到全局作用域
-
作用域链:
-
在nodejs中,作用域链的顺序是:局部作用域 -> 模块作用域 -> 全局作用域
-
在浏览器中,作用域链的顺序是:局部作用域 -> 全局作用域。
-
-
在浏览器环境中,全局作用域通常是
window对象,而在Node.js环境中,则是global对象 -
var指向、this指向的作用域的也会有区别
-
在nodejs中,module.exports、exports、this 指向同一个对象
var指向问题
- nodejs中,使用 var 在全局作用域中声明的变量不会成为全局对象的属性
- 浏览器中,浏览器中,var在全局范围内声明,则会成为全局作用域的变量,会绑定到window全局作用域中
// nodejs环境
var name = 'nodejs' // nodejs中,使用 var 关键字在全局作用域中声明的变量不会成为全局对象的属性
console.log(this.name) // undefined
// 浏览器环境
var name = 'nodejs' // 浏览器中,var在全局范围内声明,则会成为全局作用域的变量,会绑定到window全局作用域中
console.log(this.name) // nodejs
this指向问题
-
nodejs中,
this在全局作用域中不再指向全局对象,而是指向当前模块的exports对象(如果你没有导出任何内容,那么它就是一个空对象)- 在模块中,export、module.exports、this会共同指向一个对象
-
浏览器中,this的指向会有几种情况,会根据指向根据环境不同而发生改变,
- 比如
- 作为对象方法调用
- this会指向调用它的对象
- 作为函数调用
- this会指向全局对象
- 作为构造函数调用
- this是指向当前new出来的对象,也就是对象实例
- 作为apply/call调用
- this会指向传入的对象
- 作为绑定事件事件调用
- this 指向触发事件的DOM元素。
- 作为对象方法调用
- 比如
事件循环
-
事件循环是一种机制,解决异步非阻塞的问题, 通过事件循环去实现异步过程,能够确保单线程环境能够执行多个任务
-
浏览器中,事件循环是 浏览器渲染主线程的工作方式,事件循环会开始一个循环,每次循环都会读取消息队列(任务队列)中的第一个任务执行
- 浏览器是多个多进程多线程的程序,事件循环是发生在渲染进程这个阶段的
- 渲染进程是浏览器中最繁忙的进程,每个进程都会默认开启一个主线程来执行具体的任务,渲染进程也会开启一个渲染主线程负责页面的渲染执行具体的任务
-
Node.js中的事件循环基于Libuv库,主要是处理io操作、定时器操作,通过异步非阻塞可以处理大量的io操作,提供系统的并发性能,同样也是浏览器的事件循环一样,会开始一个循环,每次循环会读取消息队列(任务队列)中的第一个任务执行
libuv是一个跨平台异步IO的库,Libuv库提供了事件循环、线程池、异步I/O等功能
nodejs的事件循环3个重要阶段部分,Timers、Poll、Check
这三个阶段的组合使得Node.js能够高效地处理异步任务,同时保证了I/O操作的非阻塞执行
- Timers(定时器):这个阶段处理通过setTimeout()和setInterval()设定的定时任务。在每次循环中,Node.js会检查是否有定时器到期,如果有,会将定时器的回调函数放入队列中等待执行。如果一个定时器设定的时间尚未到,它不会被执行。
- Poll(轮询):这个阶段是Node.js处理I/O操作的核心部分。在这个阶段,Node.js会检索新的I/O事件,比如从文件系统中读取文件或者从网络中接收数据。当没有新的事件时,Node.js会等待事件的到来。当有事件触发时,它会执行回调函数,并且如果有设置了定时器,也会检查定时器是否到期。
- Check(检查):在这个阶段,setImmediate()设定的回调函数会被执行。这个阶段的执行在Poll阶段之后,保证了在执行完I/O事件后立即执行这些回调函数