ES6
什么是ECMAScript:
是由Ecma国际通过ECMA-262标准化的脚本程序设计语言。
什么是ECMA-262:
Ecma国际制定了许多标准,而ECMA-262只是其中的一个。
作用域:
目标:了解作用域对程序执行的影响及作用域链的查找机制,使用闭包函数创建隔离作用域避免全局变量污染。
作用域(scope)规定了变量能够被访问的“范围”,离开了这个“范围”变量便不能被访问,
作用域分为:
局部作用域
函数作用域:在函数内部声明的变量只能在函数内部被访问,外部无法直接访问
块作用域:在javascript中使用 { } 包裹的代码称为代码块,代码块内部声明的变量外部将【有可能】无法被访问(var声明的变量可以被访问,var没有作用域)
全局作用域
<script>标签和 .js文件的【最外层】就是所谓的全局作用域,在此声明的变量在函数内部也可以被访问。全局作用域中声明的变量,任何其他作用域都可以被访问。
作用域链:
作用域链本质上是底层的变量查找机制
在函数执行时,会优先查找当前函数作用域中查找变量
如果当前作用域差找不到则会一次逐级查找父级作用域直到全局作用域
垃圾回收机制(GC):
js中内存的分配和回收都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收。
内存的生命周期:
内存分配:当我们声明变量、函数、对象的时候,系统会自动为他们分配内存
内存使用:即读写内存,也就是使用变量、函数等
内存回收:使用完毕,由垃圾回收器自动回收不再使用的内存
(全局变量一般不会回收。而局部变量不用了,会被回收掉)
垃圾回收机制——算法说明
引用计数法
ie采用的引用的计数算法,定义“ 内存不再使用 ”,就是看一个对象是否有指向它的引用,没有引用了就回收对象
算法:
跟踪记录被引用的次数
如果被引用了一次,那么就记录次数1,多次引用会累加
如果减少一个引用就减1
如果引用次数是0,则释放内存
缺点:
引用计数:
如果两个对象相互引用,尽管他们不再使用,垃圾回收器不会进行回收,导致内存泄露。(嵌套引用(循环引用))。
因为引用的次数永远不会是0。这样的相互引用如果说很大量的存在就会导致大量的内存泄露。
标记清除法
现代的浏览器已经不再使用引用计数算法了。
现代浏览器通用的大多是基于标记 清除 算法的某些改进算法,总体思想都是一致的。
核心:
标记清除算法将“ 不再使用的对象 ” 定义为“ 无法达到的对象 ”。
就是从根部(在js中就是全局对象) 出发定时扫描内存中的对象 。凡是能从根部到达的对对象,都是还需要使用的。
那些无法由根部出发触及到的对象被标记为不再使用,稍后进行回收。
闭包:
概念:一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域。(闭包 = 内层函数 + 外层函数的变量)
闭包应用:实现数据的私有
优势:
不用闭包,使用全局变量,会导致变量直接被修改,而使用闭包实现了数据私有,保护了数据。
对比使用普通函数的方法,闭包可以让函数正常运行。
劣势:
闭包导致变量不会被垃圾回收机制所清除,会大量消耗内存
有内存泄露的风险
讲解原理的博客:
https://www.cnblogs.com/dengyao-blogs/p/11475575.html
变量和函数提升:
变量提升
变量提升允许在变量声明之前即可被访问(仅存在于var声明变量)
把所有var声明的变量提升到当前作用域的最前面
只提升声明,不提升赋值
正因为如此ES6引入了块级作用域。用let或const声明变量,让代码写法更具规范和人性化。
注意:
1,变量在未声明被访问会报语法错误
2,变量在var声明之前被访问,变量的值为undefined
3,let / const 声明的变量不存在变量提升
4,变量提升出现在相同作用域中
5,实际开发中推荐先声明再访问变量
函数提升:
会把所有函数声明提升到当前作用域的最前面。
只提升函数声明,不提升函数调用
函数表达式必须先声明和赋值后调用否则报错
函数进阶:
动态参数
使用函数时,当不确定传递多少个实参的时候,我们可以用arguments,是函数内部内置的伪数组变量,它包含了调用函数时传入的所有实参吧
剩余参数:
剩余参数允许我们将一个不定数量的参数表示为一个数组
... 是语法符号,置于最末函数形参之前,用于获取多余的实参
借助 ... 获取的剩余实参,是个真数组
开发中,提倡多使用剩余参数
展开运算符
展开运算符(...)将一个数组进行展开
用途:
求最大值与合并数组
箭头函数:
1,const fn = ( ) => { }
2,const fn = x => { } (只有一个形参的时候,可以省略小括号)
3.const fn = x => console.log( x ) (只有一行代码的时候,可以省略大括号,并且无需写 return 直接返回值 )
4,函数箭头可以直接返回一个对象 const fn = uname => ( { uname: uname } )
箭头函数this :
1,在箭头函数出现之前,每一个新函数根据它是被如何调用的来定义这个函数的this值,非常麻烦。箭头函数不会创建自己this,它只会从自己的作用域链的上一层沿用this。
2,箭头函数不会创建自己的this,它只会从自己的作用域链的上一层沿用this。
3,在开发中{ 使用箭头函数需要考虑函数中this的值 },事件回调函数使用箭头函数时,this为全局的window,因此DOM事件回调函数为了简便,还是不太推荐使用箭头函数。