- 堆
堆是指一块已分配的用来存储所需数据的存储空间(内存)。 对象的值被分配在一个堆中,并用一个地址记录该值存储的位置, 这个地址存储在命名对象的变量(内存,也可以说栈内存)中。 所以复制这个变量只是复制了引用地址,而不是复制了这个对象。
- 栈 (先进后出)
栈可以看作一个按照顺序排列的消息数据(事件)集合。 这个集合可以看作是一个内部嵌套了一个方法的函数, 而这个内部方法又嵌套了一个方法,就这么嵌套了N层。 当执行这个方法时,需要先执行内部的方法,也就是要先执行最内部的方法,然后就是等内部的一层层方法按照嵌套层级的反向顺序执行完毕,才能执行最外层的方法。 所以当你执行这么一个方法(栈)时,就是要先执行“最后来的方法”,所以叫做先进后出。 JavaScript是单线程语言,主线程执行同步代码。 函数调用时, 便会在内存中形成了一个“调用记录”, 又称“调用帧”, 保存调用位置和内部变量等信息。 如果函数内部还调用了其他函数,那么在调用记录上方又会形成一个调用记录,
所有的调用记录就形成一个“调用栈”。(闭包、尾调用、尾递归优化) - 队列 (先进先出)
队列也可以看作是指一个按照顺序排列的消息事件集合。 区别就是队列像一个直线单向传送带,先传送到终点的物品,先进行处理。
- 总结与拓展
javaScript是单线程的,不能同时执行多个任务,单线程就意味着所有任务需要排队。 但是在javaScript里面,很多时候阻止线程运行的很慢的是网络IO之类; 这时候CPU是空闲的,这样就会造成资源的浪费,所以javaScript在主线程之外实现了一个任务队列, 像IO之类比较慢的操作暂时都会挂在任务队列上,这样不会影响到主线程上任务的执行, 等到IO的响应回来后再回到主线程上来执行挂起的任务。 比如Ajax请求、定时器等、UI事件等都会先进入到任务队列上,而不是挂在主线程上。
任务队列里的每个任务都可以看作是一个由多个事件组成的(任务)栈,所以这个任务队列就可以看作一个由多个(任务)栈组成的队列,
当这个队列中的某一个(任务)栈执行完毕(清空)以后,就会把这个(任务)栈移除,然后在主线程上面执行该(任务)栈返回的最终消息。 这个处理过程包含了调用与这个消息相关联的函数(以及因而创建的一系列初始堆栈帧)。 当栈为空的时候,也就意味着消息处理结束。 这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。JS是单线程, 主线程执行同步代码, 事件、I/O操作等异步任务,将会进入任务队列执行,异步执行有结果之后,就会变为等待状态, 形成一个事件,
主线程的同步代码执行完之后,再从”任务队列”中读取事件, 执行事件异步任务的回调。 这就是为什么执行顺序是, 同步 > 异步 > 回调
更简单的说:只要主线程空了(同步),就会去读取”任务队列”(异步),这就是JavaScript的运行机制。