好程序员web前端培训分享JavaScript学习笔记闭包与继承,闭包:闭包是我们函数的一种高级使用方式,在聊闭包之前我们要先回顾一下函数

函数的两个阶段我们一直说函数有两个阶段定义阶段调用阶段开辟一个存储空间把函数体内的代码一模一样的放在这个空间内(不解析变量)把存储空间的地址给函数名按照函数名的地址找到函数的存储空间形参赋值预解析将函数存储空间中的代码拿出来执行(才解析变量)按照函数名的地址找到函数的存储空间形参赋值预解析在内存中开辟一个执行空间将函数存储空间中的代码拿出来在刚刚开辟的执行空间中执行执行完毕后,内存中开辟的执行空间销毁函数定义阶段函数调用阶段重新定义函数调用阶段

functionfn(){

console.log('我是 fn 函数')}fn()

函数执行的时候会开辟一个执行空间(我们暂且叫他xxff00)console.log('我是 fn 函数')这个代码就是在xxff00这个空间中执行代码执行完毕以后,这个xxff00空间就销毁了每一个函数会有一个存储空间但是每一次调用都会生成一个完全不一样的执行空间并且执行空间会在函数执行完毕后就销毁了,但是存储空间不会那么这个函数空间执行完毕就销毁了,还有什么意义呢?我们可以有一些办法让这个空间不销毁闭包,就是要利用这个不销毁的执行空间函数的执行空间会在函数执行完毕之后销毁但是,一旦函数内部返回了一个引用数据类型,并且在函数外部有变量接受的情况下那么这个函数执行空间就不会销毁了函数执行空间函数执行空间不销毁

functionfn(){

constobj={

name:'Jack',

age:18,

gender:'男'

}

returnobj}consto=fn()

函数执行的时候,会生成一个函数执行空间(我们暂且叫他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

// 这个函数给一个名字,方便写笔记returnfunctiona(){

console.log(num)

}}constf=fn()

fn()的时候会生成一个xxff00的执行空间再xxff00这个执行空间内部,定义了一个a函数的存储空间xxff11全局f 变量接受的就是xxff00里面的xxff11所以xxff00就是不会销毁的空间因为xxff00不会销毁,所以,定义再里面的变量 num 也不会销毁将来f()的时候,就能访问到 num 变量为什么要叫做特点,就是因为他的每一个点都是优点同时也是缺点闭包的特点作用域空间不销毁优点:因为不销毁,变量页不会销毁,增加了变量的生命周期缺点:因为不销毁,会一直占用内存,多了以后就会导致内存溢出

可以利用闭包访问再一个函数外部访问函数内部的变量优点:可以再函数外部访问内部数据缺点:必须要时刻保持引用,导致函数执行栈不被销毁

保护私有变量优点:可以把一些变量放在函数里面,不会污染全局缺点:要利用闭包函数才能访问,不是很方便有一个A 函数,再 A 函数内部返回一个 B 函数再A 函数外部有变量引用这个 B 函数B 函数内部访问着 A 函数内部的私有变量以上三个条件缺一不可继承是和构造函数相关的一个应用是指,让一个构造函数去继承另一个构造函数的属性和方法所以继承一定出现在两个构造函数之间我们之前说,构造函数(类)是对一类行为的描述那么我们类这个概念其实也很抽象比如:我们说国光/富士都是 苹果的品种,那么我们就可以写一个苹果类来实例化很多品种出来而苹果/梨这些东西都是水果的一种,那么我们就可以写一个水果类说过的统一特点就是甜/水分大,而不同的水果有不同的特征那么我们就可以让苹果类来继承水果类的内容,然后再用水果类去实例化对象那么实例化出来的就不光有苹果类的属性和方法,还有水果类的属性和方法其实说到底,到底什么是继承我们之前说,在我们书写构造函数的时候,为了解决一个函数重复出现的问题我们把构造函数的方法写在了prototype上闭包概念(熟读并背诵全文)继承一个小例子继承的作用

这样,每一个实例使用的方法就都是来自构造函数的prototype上就避免了函数重复出现占用内存得到情况那么,如果两个构造函数的prototype 中有一样的方法呢,是不是也是一种浪费所以我们把构造函数䣌prototype 中的公共的方法再次尽心提取

我们准备一个更公共的构造函数,让构造函数的__proto__指向这个公共的构造函数的prototype我们有一些常见的继承方式来实现和达到继承的效果我们先准备一个父类(也就是要让别的构造函数使用我这个构造函数的属性和方法)常见的继承方式

functionPerson(){

this.name='Jack'}Person.prototype.sayHi=function(){

cosnole.log('hello')}

这个Person构造函数为父类让其他的构造函数来继承他当别的构造函数能够使用他的属性和方法的时候,就达到了继承的效果原型继承,就是在本身的原型链上加一层结构原型继承

functionStudent(){}Student.prototype=newPerson()

借用构造函数继承把父类构造函数体借用过来使用一下而已

functionStudent(){

Person.call(this)}

组合继承就是把原型继承和借用构造函数继承两个方式组合在一起

functionStudent(){

Person.call(this)}Student.prototype=newPerson

ES6 的继承es6 的继承很容易,而且是固定语法
// 下面表示创造一个 Student 类,继承自 Person 类

classStudentextendsPerson{

constructor(){

// 必须在 constructor 里面执行一下 super() 完成继承super()

}}

这样就继承成功了