闭包
函数的两个阶段
定义阶段
-
在内存中开辟一个空间
-
将函数的代码,存储到这个空间中(堆空间、不会进行预解析)
-
将空间对象的地址赋值给函数名或变量
调用阶段
-
根据函数名或变量中存储的地址、找到对应的存储空间
-
形参赋值
-
预解析
-
执行函数
重新解释函数的调用阶段
-
根据函数名或变量中存储的地址、找到对应的存储空间
-
形参赋值
-
预解析
-
在内存中开辟一个执行空间专门存储要执行的函数的代码
-
在执行空间中执行函数代码
-
执行结束,执行空间销毁
让执行空间不被销毁的条件
-
在函数中返回一个引用数据类型
-
在函数外部有一个变量一直引用着这个函数返回的引用数据类型
销毁条件:当该变量不在引用这个函数返回的值时,该执行空间就会被销毁
闭包
形成闭包的条件
简单来说就是函数要有一个不被销毁的执行空间
-
在函数A内,返回着一个函数B
-
函数A外部,有一个变量一直引用着函数A返回的函数B
-
函数B内部,访问着函数A的私有变量
闭包的特点
-
作用域空间不被销毁
优点:延长变量的生命周期
缺点:占用空间,导致内存溢出
-
函数外部可以使用函数内部的数据
优点:函数外部可以使用函数内部的数据
缺点:只能通过闭包的形式访问,不方便
-
保护变量
优点:不污染全局
缺点:只能通过闭包访问,不方便
继承
让一个一个构造函数去拥有另一个构造函数的属性和方法
继承一定是出现在两个构造函数之间
作用:能够解决一个函数重复出现的问题、避免函数重复造成内存占用的情况
原型继承
function Person(){} function Student(){} Student.prototype = new Person // 在原型链指向被继承构造函数的实例上
优点:构造函数体内和原型上的都可以继承
缺点:一个构造函数的内容,在两个位置进行传参、继承来的属性不在子类实例身上
借用构造函数继承
function Person(){} function Student(){ Person.call(this) } //改变实例对象Person的this指向达到可以访问Person里面方法的效果
优点:继承来的属性在自己身上、在一个实例化过程传递参数
缺点:只能继续父类构造函数体内的内容、父类原型上的内容不能继承
组合继承
function Person(){} function Student(){ Person.call(this) } Student.prototype = new Person // 在原型链指向被继承构造函数的实例上 //改变实例对象Person的this指向达到可以访问Person里面方法的效果
优点:父类构造函数体内和原型上的内容都能继承、继承的属性在自身上、在一个位置传递参数
缺点:给子类添加方法,实际上是给父类的实例添加方法
ES6的继承
function Person(){} //创建一个Student类,继承Person class Student extends Person{ constructor(){//必须在constructor里面执行super()才能完成继承 super()//表示父类的含义(Person) } }
super( ) 等价于 Person.call (this) super 必须写在 constructor 里面 属于自己的属性要写在super后面