一.作用域和自由变量
1.作用域
1.全局作用域:js中首先有一个最外层的作用域就叫做全局作用域。
2.函数作用域:js中可以通过函数来创建一个独立作用域称为函数作用域,函数可以嵌套,所以作用域也可以嵌套。
3.块级作用域:es6中新增了块级作用域
(大括号,比如:if{},for(){},while(){}…)。
2.自由变量
1.自由变量:就是当前作用域没有定义的变量。
2.作用域链:自由变量的向上级作用域一层一层查找,直到找到为止,最高找到全局作用域,就形成了作用域链。
3.变量提升:var声明的变量,function声明的函数存在变量提升,let const 不会变量提升。
二.闭包,this问题
1.闭包
能够访问外部函数内部变量的函数就是闭包
1.作用域应用的特殊情况,有两种表现
1.1.函数作为参数被传递
1.2.函数作为返回值被返回
2.闭包的优点
2.1保护函数内变量的安全,加强封装性
2.2方便调用上下文的局部变量
3.闭包的缺点
3.常驻内存,会增大内存使用量,使用不当很容易造成内存泄露
2.This
1.普通函数this指向window
2.对象方法中的this指向的是对象本身
3.call()/apply()/bind()都可以改变this指向,指向的是第一个参数,不同点:bind()需要手动执行,call()第二个参数为单个数值,apply()第二个参数为数组。
4.class中的this指向new后的实例对象
5.箭头函数的this指向的是父级上下文中的this
三.js异步之宏任务(marcroTask)和微任务(microTask)
宏任务包括:setTimeout setInterval Ajax DOM事件
微任务:Promise async/await
微任务比宏任务的执行时间要早
1.同步和异步的区别
同步会阻塞程序执行
异步不会阻塞程序执行 (
- 定时任务:setTimeout,setInverval
- 网络请求:ajax请求,动态
<img>
加载 - 事件绑定
)
2.事件循环机制
1)所有的同步任务都在主线程上执行,行成一个执行栈。
2)除了主线程之外,还存在一个任务列队,只要异步任务有了运行结果,就在任务列队中植入一个时间标记。
3)主线程完成所有任务(执行栈清空),就会读取任务列队,先执行微任务队列在执行宏任务队列。
4)重复上面三步。
执行顺序:主线程 >> 主线程上创建的微任务 >> 主线程上创建的宏任务
四.js垃圾回收和内存泄露
1.垃圾回收机制
1.浏览器的 Javascript 具有自动垃圾回收机制,垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。但是这个过程不是实时的,因为其开销比较大并且GC时停止响应其他操作,所以垃圾回收器会按照固定的时间间隔周期性的执行。
2.只有函数内的变量才可能被回收
1.1标记清除
js中最常用的垃圾回收方式就是标记清除。当变量进入环境时,例如,在函数中声明一个变量,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。
1.2引用计数
引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。如果同一个值又被赋给另一个变量,则该值的引用次数加 1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减 1。当这个值的引用次数变成 0 时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当垃圾回收器下次再运行时,它就会释放那些引用次数为 0 的值所占用的内存。
2.内存泄漏
不再用到的内存,没有及时释放,就叫做内存泄漏
1.Vue中的内存泄漏
1.1在mounted/created钩子中使用JS绑定了DOM/BOM对象中的事件或使用第三方库初始化,则需要在beforeDestroy做对应销毁处理
1.2如果组件中使用了 setInterval
,需要在 beforeDestroy
中做对应销毁处理;
3.JS中的内存泄漏
1.循环引用
2.闭包
3.DOM泄漏
4.定时器泄漏