Open tomoya06 opened 4 years ago
如果同时注册捕获和冒泡,则按注册顺序执行:
// 以下会先打印冒泡然后是捕获
node.addEventListener(
'click',
event => {
console.log('冒泡')
},
false
)
node.addEventListener(
'click',
event => {
console.log('捕获 ')
},
true
)
如果一个节点中的子节点是动态生成的、或者子节点是列表,那么子节点需要注册事件的话应该注册在父节点上。事件代理的方式相对于直接给目标注册事件来说,优点有:可以节省内存;子节点变化时也不需要给子节点注销事件。
JavaScript程序每次创建字符串、数组或对象时,解释器都必须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便他们能够被再用,否则,JavaScript的解释器将会消耗完系统中所有可用的内存,造成系统崩溃。
简单来说,垃圾回收就是找出不再使用的变量,然后释放掉其占用的内存,但是这个过程不是实时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行。
这是javascript中最常用的垃圾回收方式。当变量进入执行环境是,就标记这个变量为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到他们。当变量离开环境时,则将其标记为“离开环境”。
标记清除的具体步骤如下:参考掘金博客
所谓"引用计数"是指语言引擎有一张"引用表",保存了内存里面所有的资源(通常是各种值)的引用次数。如果一个值的引用次数是0,就表示这个值不再用到了,因此可以将这块内存释放。
有个问题是循环引用,可能互相引用的两个变量已经离开作用域了但引用数都不为0,无法清除。为了避免循环引用导致的内存泄漏问题,截至2012年所有的现代浏览器均放弃了这种算法。
V8的垃圾回收策略主要是基于分代式垃圾回收机制,其根据对象的存活时间将内存的垃圾回收进行不同的分代,然后对不同的分代采用不同的垃圾回收算法。
上图带斜纹的区域表示暂未使用。
新生代中的对象一般存活时间较短,使用 Scavenge GC 算法。
在新生代空间中,内存空间分为两部分,分别为 From 空间和 To 空间。在这两个空间中,必定有一个空间是使用的,另一个空间是空闲的。新分配的对象会被放入 From 空间中,当 From 空间被占满时,新生代 GC 就会启动了。
老生代中的对象一般存活时间较长且数量也多,使用了两个算法,分别是标记清除算法和标记压缩算法。
新生代的对象在如下情况时会被移动到老生代 aka. 对象晋升:
标记清除算法与上一节介绍的相同。在标记清除执行之后,内存空间可能会出现不连续的状态,也就是出现内存碎片,因此需要做标记压缩。
标记压缩的过程中,会将活动的对象往堆内存的一端进行移动,移动完成后再清理掉边界外的全部内存。
JavaScript有一个基于事件循环的并发模型,事件循环负责执行代码、收集和处理事件以及执行队列中的子任务。
JS 在执行的过程中会产生执行环境,这些执行环境会被顺序的加入到执行栈中。如果遇到异步的代码,会被挂起并加入到Task队列中。一旦执行栈为空,Event Loop 就会从 Task 队列中拿出需要执行的代码并放入执行栈中执行。本质上来说 JS 中的异步还是同步行为。
不同的任务源会被分配到不同的 Task 队列中,任务源可以分为 微任务(microtask) 和 宏任务(macrotask)。
new Promise(F)
的F
还是作为script直接执行的分析总结来自思否博客
模块化
ES6
common js
node独有
module.exports vs exports
参考内部实现:
AMD
没用过。参考这里