Devin Deng
Devin Deng
组内每周都会有分享总结会,昨晚分享的课题是`Event Loop`,我很积极且有点自信地答了几道题,结果被虐的`体无完肤`,果然有些东西不经常回顾就容易忘,于是花一晚上`挑灯夜战`重新做了一份有关`event loop`的知识总结,在此分享给大家,希望对各位看官有所帮助,看完有收获的同学还请积极点赞,讲的不对的地方,望指出,我会及时修正,谢谢~ ## 浏览器端 > 浏览器端的event loop基于javascript中的`堆/栈/任务队列`,任务队列又分为`宏任务`与`微任务` ##### 每次事件循环的时候: * 微任务/宏任务在`相同作用域下`,会先执行微任务,再执行宏任务 * `宏任务处于微任务作用域下`,会先执行微任务,再执行微任务中的宏任务 * `微任务处于宏任务作用域下时`,会先执行宏任务队列中的任务,然后再执行微任务队列中的任 务,在当前的微任务队列没有执行完成时,是不会执行下一个宏任务的。 本文主要讲解的还是Node,对于浏览器端event loop的具体分析及证明可以查看这篇文章[探究javascript中的堆/栈/任务队列与并发模型 event loop的关系](https://juejin.im/post/5cda8192f265da035e2147b5) ## Nodejs端 ### nodejs 的事件循环分为`6个阶段`,每个阶段都有1个任务队列,微任务在事件循环的各个阶段之间执行  #### timers 阶段:...
## 理解this作用域 《javascript高级程序设计》中有说到: >this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window ,而当函数被作为某个对象调用时,this等于那个对象。不过,`匿名函数具有全局性,因此this对象同常指向window` 不过,`在全局函数中,this等于window`,`匿名函数具有全局性,因此this对象通常指向window`,针对于匿名函数this具有全局性的观点仍是有争议的,可参考 https://www.zhihu.com/question/21958425 ## this的指向取决于函数(不包含箭头函数)执行时的环境 ### 验证过程如下: 关于闭包经常会看到这么一道题: ```javascript var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return...
## 作用域链(Scope Chain) 在JavaScript中,函数也是对象,实际上,JavaScript里一切都是对象。函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。 在函数add创建时,它的作用域链中会填入一个全局对象,该全局对象包含了所有全局变量,函数add的作用域将会在执行时用到 ```javascript function add(num1,num2) { var sum = num1 + num2; return sum; } ``` 执行此函数时会创建一个称为“运行期上下文(execution context)”的内部对象,运行期上下文定义了函数执行时的环境。每个运行期上下文都有自己的作用域链,用于标识符解析,当运行期上下文被创建时,而它的作用域链初始化为当前运行函数的[[Scope]]所包含的对象。 这些值按照它们出现在函数中的顺序被复制到运行期上下文的作用域链中。它们共同组成了一个新的对象,叫“活动对象(activation object)”,该对象包含了函数的所有局部变量、命名参数、参数集合以及this,然后此对象会被推入作用域链的前端,当运行期上下文被销毁,活动对象也随之销毁。 在函数执行过程中,每遇到一个变量,都会经历一次标识符解析过程以决定从哪里获取和存储数据。该过程从作用域链头部,也就是从活动对象开始搜索,查找同名的标识符,如果找到了就使用这个标识符对应的变量,如果没找到继续搜索作用域链中的下一个对象,如果搜索完所有对象都未找到,则认为该标识符未定义。函数执行过程中,每个标识符都要经历这样的搜索过程。 ## 作用域链和代码优化 从作用域链的结构可以看出,在运行期上下文的作用域链中,标识符所在的位置越深,读写速度就会越慢。如上图所示,因为全局变量总是存在于运行期上下文作用域链的最末端,因此在标识符解析的时候,查找全局变量是最慢的。所以,在编写代码的时候应尽量少使用全局变量,尽可能使用局部变量。一个好的经验法则是:如果一个跨作用域的对象被引用了一次以上,则先把它存储到局部变量里再使用。例如下面的代码: ```javascript function changeColor(){...
### new 运算符 >在js中,new()常被用来创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例 本文,主要讲如何手写function new创建实例并实现js继承 #### 对于想彻底捋清楚new做了哪些操作的同学,可以查看我的这篇文章: [【Javascript】彻底捋清楚javascript中 new 运算符的实现](https://github.com/AwesomeDevin/blog/issues/7) ### 手写实现 new() ```javascript function subNew(){ var obj = {} 将父级的原型prototype指向子级的隐式原型__proto__ obj.__proto__ = Parent.prototype //创建实例的时候传参 var res = Parent.call(obj,...arguments)...
### 堆/栈/队列 在javascript中,存在`调用栈 (call stack)`和`内存堆(memory heap)` ,程序中函数依次进入栈中等待执行,若执行时遇到异步方法,该异步方法会被添加到用于回调的`任务队列(task queue)`中,【即JavaScript执行引擎的单线程拥有一个调用栈、内存堆和一个任务队列】 >调用栈 (call stack):CallStack是用来处理函数调用与返回的。特点是先进后出,每次调用一个函数,Javascript运行时会生成一个新的调用结构压入CallStack。而函数调用结束返回时,JavaScript运行时会将栈顶的调用结构弹出。由于栈的LIFO特性,每次弹出的必然是最新调用的那个函数的结构。**函数调用会形成了一个堆栈帧,存放基本数据类型的变量** >内存堆(memory head):**引用数据类型被存放在堆中**,在我们进行浅复制时,我们改变的只是引用数据类型在栈内存中的引用地址,实际上它在堆内存中的引用地址仍然没有发生变化 >任务队列(task queue):javaScript 运行时包含了一个待处理的任务队列。 ### 并发模型 与 EventLoop javascript引擎是单线程的,它的并发模型基于`Event Loop(事件循环)` >当线程中的同步任务执行完,`执行栈`为空时,则从`任务队列(task queue)`中取出异步任务进行处理。这个处理过程包含了调用与这个任务相关联的函数(以及因而创建了一个初始堆栈帧)。当`执行栈`再次为空的时候,也就意味着该任务处理结束,从任务队列中取出下一个异步任务进行处理,不断重复,这个过程是循环不断的, 所以整个的这种运行机制又称为`Event Loop(事件循环)`.  ### Task Queue...
### 题目 给你一个整数n. 从 1 到 n 按照下面的规则打印每个数: - 如果这个数被3整除,打印fizz - 如果这个数被5整除,打印buzz. - 如果这个数能同时被3和5整除,打印fizz buzz. - 如果这个数既不能被 3 整除也不能被 5 整除,打印数字本身。 比如 n = 15, 返回一个字符串数组: ```javascript [ "1", "2",...
### 题目 给出一个具有重复数字的列表,找出列表所有不同的排列。 样例 样例 1: 输入:[1,1] 输出: [ [1,1] ] 样例 2: 输入:[1,2,2] 输出: [ [1,2,2], [2,1,2], [2,2,1] ] 挑战 使用递归和非递归分别完成该题。
### 题目 给定一个只含非负整数的m*n网格,找到一条从左上角到右下角的可以使数字和最小的路径。 输入: [[1,3,1],[1,5,1],[4,2,1]] 输出:7 路线为: 1 -> 3 -> 1 -> 1 -> 1。 ### JS实现 ```javascript function fn(arr){ for(var i in arr) { for(var j in arr[0]){...
### 题目描述 我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法? ### JS实现 ```javascript function rectCover(number) { // write code here if(number
### 题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。 ### JS实现 ```javascript function minNumberInRotateArray(rotateArray) { // write code here if(rotateArray.length == 0) { return 0 } return Math.min(...rotateArray) } ```