1. 闭包
① 作用域
变量的作用域:全局变量和局部变量
函数内部可以直接读取全局变量,但是在函数外部无法读取函数内部的局部变量
在函数A内部,再定义一个函数B,A内部的所有局部变量,对B都是可见的,B内部的局部变量,对A是不可见的,这就是 "链式作用域"结构(chain scope)
B函数就是闭包,能够读取其他函数内部变量的函数
②用途
第一 可以读取函数内部的变量
第二 就是让这些变量的值始终保持在内存中,不会在A调用后被自动清除
因为A是B的父函数,B要是被赋给了一个全局变量,这导致B始终在内存中,而B的存在依赖于A,故A也始终在内存中,就不会在调用结束后,被垃圾回收机制(garbage collection)回收。
③ 使用闭包的注意点
闭包使函数中的变量被保存在内存中,内存消耗很大,不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露。
解决方法是,在退出函数之前,将不使用的局部变量全部删除。(怎么删除?)
闭包会在父函数外部,改变父函数内部变量的值。不要随便改变父函数内部变量的值。
2. 闭包造成的内存泄露 原因及解决方法
内存是根据对象的创建分配给对象的,没有对该对象引用的时候就会收回。
内存泄漏:一块被分配的内存既不能使用,也不能回收。从而影响性能,甚至导致程序崩溃。
垃圾自动回收机制会找出那些不再继续使用的变量,释放其占有的内存。
闭包使函数中的变量被保存在内存中,内存消耗很大,可能导致内存管理器不能正确解读JavaScript变量的生命周期,没有释放其内存,而也没有再被使用。
(虽然浏览器自带多种js内存垃圾回收机制,但是这几种垃圾回收机制都不能及时的实现垃圾回收)
解决方法:让 javascript 对象为空,手动给它赋值一个空值null
(如果是IE 6, 内存泄漏,直到关闭IE进程为止。如果是IE 7,内存泄漏, 直到离开当前页面为止。)
3. 如何排查内存泄漏
按下F12调出调试工具,点击“Profiles”标签。
该面板可以监控CPU、CSS和内存,选中“Take Heap Snapshot”,点击“Start”按钮,拍当前js的heap快照,右边视图就会列出heap里的对象列表,点击左上角的圆圈圈,就出现第二个内存快照
切换到comparison(对照)选项,就会出现两个视图的对象差异
看closure(闭包),如果#delta为证书,则表示创建了闭包函数,要是多个快照都没有变负数,表示没有销毁闭包
4. 垃圾回收机制
标记清除(mark and sweep)
变量进入执行环境的时候,比如函数中声明一个变量,垃圾回收器将其标记为“进入环境”
当变量离开环境的时候(函数执行结束)将其标记为“离开环境”
在运行的时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后。垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间
引用计数
引用计数的含义是跟踪记录每个值被引用的次数。
当声明了一个变量并赋值给该变量时,则这个值的引用次数就是1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数就减1。当这个引用次数变成0时,则说明没有办法再访问这个值了,因而就可以将其所占的内存空间给收回来。这样,垃圾收集器下次再运行时,它就会释放那些引用次数为0的值所占的内存。
4. js定时器机制 原理
js是单线程的,对浏览器来说js是其中一条
解决单线程引入了异步机制 浏览器是多线程的
其他线程是通过js引擎线程执行到某个特定功能之后指定给浏览器对应的线程
JS引擎线程首先执行回调函数块,然后是执行点击事件回调,接着是执行定时器的线程,最后在执行其他的线程。
setTimeout我们可以定义为:
在指定时间内, 将任务放入事件队列,等待js引擎空闲后被执行.