作用域
为什么要区分作用域:防止全局污染,把所有的变量划分到各个模块
作用域分为:全局作用域,局部作用域(局部分为块级作用域,函数作用域)
全局变量的缺点:所有人都可以随意访问,这种数据叫做公共数据,容易被篡改,导致出现一些严重的 bug
垃圾回收机制
引用计数法
最初的一种垃圾回收机制叫做:引用计数法 ,它的原理是统计所有对象的引用计数,只要没有人引用对象了(零引用),就会被回收掉
总结:引用计数法就是计算堆内存中的对象被引用了多少次,当计算为零时就会被当成垃圾回收掉
致命缺点:当循环引用时,就是两个变量相互引用,哪怕没有其他引用,这两个变量的计数也是为 1 ,此时 这两个变量永远不会被删除,这就造成了内存泄漏,所以在2012年以后所有现代浏览器都取消了这种算法,取而代之的是标记清除法
什么是引用?
对象存储在堆内存空间中,会被分配一个地址值,将地址值付给对应的变量,此时就可以叫做 这个对应的变量引用着对象
内存泄漏
程序中分配的内存由于某种原因程序未释放或无法释放叫做内存泄漏
标记清除法
标记清除法是什么?:假定全局作为根开始,从上至下一层一层往局部去标记所有对象,标记完之后,哪些对象没有标记则会被当成垃圾清除掉
我们还可以将这个过程想象成从根溢出一大桶油漆,它流经所有引用并标记所有可到达的对象。然后移除未标记的。
一些优化建议:
-
分代收集 系统会判断有哪些对象长期使用不回收,系统就降低这部分的扫描频率,对于经常回收的,会重点扫描
-
增量收集 在上一次的基础上新增了一些对象,就进行收集这些内容,类似于游戏打补丁
-
闲时收集 CPU 空闲时尝试运行,如果在高峰期就暂时不 GC(垃圾回收)
闭包
闭包是指函数嵌套时,内层函数访问外层函数的局部变量
1.一旦发生闭包,意味着外层函数的局部变量不会随着函数的结束而释放,会长期存在一个叫 closure (闭包) 的空间中
-
闭包会导致内层泄漏,但是这种内层泄漏是必要的,我们是无法阻止的,只能说少用闭包,但是必须用的时候还是要用的
什么是闭包总结:
闭包是什么?闭包就是函数的嵌套,内层函数访问了外层函数的局部变量
闭包有什么用?实现变量的私有化,让外部的人无法修改内部的变量
闭包会产生什么问题或现象?1.内存泄漏 2.本该释放的变量,无法及时释放,会存在闭包空间中
变量提升
变量声明的提升,仅限于 var ,变量声明只会提升声明操作,不会提升赋值操作,而这样会导致在变量赋值之前都是 undefined ,使用起来经常会出 bug
函数提升
作用:可以提升声明和整个函数体,意味着我们可以把调用函数的代码在声明函数之前,可以提高编码的灵活性
函数提升分为两种:函数声明提升、函数表达式的声明提升
1.函数声明提升:(用的更多)
2.函数表达式的声明提升:
arguments 对象
arguments 是一个对象,控制台打印为伪数组,它非常特殊,只存在 function 函数中,这个伪数组装着所有的实参(严格模式【arguments .callee】下 arguments 不能使用)
面试题:聊一聊 arguments 这个对象?
arguments 已经被淘汰了,原因有两个:
1.剩余参数的出现(出现 ES6 新特性)
2.性能问题(arguments 是一个伪数组,仅存在 function 中,它的作用是装载着所有的实参,因为 arguments 是动态伪数组,数据变化带来的性能损耗较大,每次都会同步更新所有的参数,如果参数过多则会出现问题 ,并且在开启严厉模式后会彻底禁用 arguments ,现在开发中基本不用 arguments 了,可以使用 剩余参数 完全替代了 arguments 的功能)
严厉模式是什么?
arguments .callee 代表函数本身,一般用于匿名函数的自调用, 后来 剩余参数 的出现,arguments不在使用了,所以 callee 自然也无法使用了,官方建议给函数起名字
剩余参数
...
箭头函数
1.箭头函数没有参数,必须写小括号,多个参数也要小括号
2.返回结果如果是对象 ,需要用 小括号包裹({})
3.箭头函数没有 arguments ,但是支持 剩余函数,剩余函数 必须要用小括号包裹
4.箭头函数只有一句代码时,可以省略大括号,同时必须省略 return
箭头函数的 this
箭头函数的 this ,指向和当前作用域的 this 指向一样,他没有自己的this 指向
解构赋值
将数组或对象里的成员解构出来,赋给变量
filter 新数组
函数内部要返回筛选条件,符合条件的会把当前遍历的元素加到新数组中,最后 filter 返回新数组