优秀程序员web前端培训JavaScript学习笔记闭包与继承,闭包:闭包是我们函数的一种高级使用方式。在讲闭包之前,我们首先要回顾一下函数的两个阶段。我们总是说函数有二段定义阶段,在调用阶段,开辟了一个存储空间,函数体中的代码正好放在这个空间里(不解析变量)。存储空间的地址给函数名,根据函数名的地址找到函数的存储空间。解析取出函数存储空间中的代码并执行(只解析变量)根据函数名的地址找到函数的存储空间。ExecutionSpace中的执行完成后,函数定义阶段、函数调用阶段销毁内存中创建的ExecutionSpace,函数调用阶段重新定义函数fn(){console.log('我是fnfunction')}fn()function执行时,会时不时地创建一个执行空间(暂且称他为xxff00吧)。console.log('我是fn函数')这段代码在xxff00的空间执行代码执行完后,xxff00的空间会被销毁。每个函数都会有一个Storage空间,但是每次调用都会产生一个完全不同的执行空间并且执行空间在函数执行完后会被销毁,但是存储空间在函数执行完后不会被销毁,有什么意义?我们可以有一些办法让这个空间不破坏闭包,也就是利用这个没有被破坏的执行空间。函数执行完毕后,函数的执行空间会被销毁。但是,一旦函数在函数内部返回一个引用数据类型,并且有一个变量被接受,那么函数执行空间就不会被破坏。函数执行空间不会被破坏。functionfn(){constobj={name:'Jack',age:18,gender:'Male'}returnobj}consto=fn()function会生成一个函数执行空间(暂且称它为xxff00)。代码在xxff00空间执行。在xxff00空间中声明了一个对象空间(xxff11)。在xxff00执行空间中,xxff11的对象地址返回函数外部对象的地址。0接受一个对象的地址,但是它是xxff00函数执行空间中xxff11的一个对象的地址。因为o变量已经和这个对象地址相关联了,所以xxff00这个空间直到什么时候才会被销毁,执行一段代码o=null这时候,o变量会和xxff00函数执行空间中关联的xxff11对象地址进行比较。那么,这个时候函数执行空间xxff00就会被销毁。闭包就是用这个函数执行不破坏空间的逻辑。形成闭包有几个条件。闭包的第一个条件是使用不破坏空间的逻辑,但不是返回对象数据类型,而是返回函数数据类型。关闭不破坏。空间functionfn(){returnfunction(){}}constf=fn()f变量接受一个fn执行空间。执行空间中的函数涉及两个函数。内部函数需要检查或使用外部函数的内部变量。函数引用外部函数中的变量functionfn(){constnum=100_//给这个函数起个名字,方便写notes_returnfunctiona(){console.log(num)}}constf=fn()fn()会生成一个xxff00的执行空间,在xxff00的执行空间内,定义了一个函数的存储空间xxff11。全局f变量接受xxff00中的xxff11,所以xxff00是不会被销毁的空间,因为xxff00不会被销毁。因此,定义里面的变量num不会被破坏。以后f()的时候,就可以访问num变量了。为什么叫特色呢?因为它的每一点都是一个优点,也是闭包的一个特点。Scopespace不销毁的优点:因为不销毁,所以变量页不会被销毁,增加了变量的生命周期缺点:因为不销毁,所以会一直占用内存,太多了会造成内存溢出。可以使用闭包访问另一个函数来访问函数外部内部变量优点:可以在函数外部访问内部数据缺点:必须时刻保持引用,这样函数执行栈才不会被破坏保护私有变量优点:可以在函数中放一些变量,不会污染全局缺点:使用闭包封装的函数只能被访问,不是很方便。有一个函数A,A函数内部返回一个函数B,A函数外部有一个变量引用。B函数在内部访问A函数内部的私有变量。以上三个条件缺一不可。它是与构造函数相关的应用,也就是说一个构造函数继承了另一个构造函数的属性和方法,所以继承必然出现在两个构造函数之间。我们之前说过构造函数(类)是一类行为了描述方便,我们类的概念其实很抽象。比如:我们说国光/富士都是苹果的品种,那么我们可以写一个Apple类实例化很多品种,苹果/梨都是水果的品种。种,那么我们可以写一个水果类,统一的特征是甜度/高水分,不同的水果有不同的特点,那么我们可以让苹果类继承水果类的内容,然后使用水果类实例化Objects不仅用Apple类的属性和方法实例化,而且用Fruit类的属性和方法实例化。出现的问题我们把构造函数的方法写在原型上Closureconcept(阅读背诵全文)继承一个小例子继承的作用这样每一个实例使用的方法都是从构造函数的原型到avoid那么,如果两个构造函数的原型有相同的方法,岂不是浪费了?所以我们再次提取构造函数原型中的公共方法,准备一个更公共的方法。构造函数,让构造函数的__proto__指向这个公共构造函数的原型。我们有一些常用的继承方法来实现和达到继承的效果。我们先准备一个父类(也就是让其他构造函数使用我的构造函数属性和方法)公共继承方法functionPerson(){this.name='Jack'}Person.prototype.sayHi=function(){cosnole.log('hello')}这个Person构造函数是父类让Other构造函数继承他。当其他构造函数可以使用他的属性和方法时,就达到了继承的效果。原型继承就是在自己的原型链上增加一层结构原型继承functionStudent(){}Student.prototype=newPerson()借用构造函数继承借用父类构造函数体并使用一段时间functionStudent(){Person.call(this)}组合继承就是把原型继承和借用构造函数继承结合在一起functionStudent(){Person.call(this)}Student.prototype=newPersonES6继承ES6继承很容易,而且是固定语法//下面的意思是创建一个Student类,继承自Person类classStudentextendsPerson{constructor(){//必须在构造函数中执行super()完成继承super()}}这样,继承就成功了
