(javascript)(基础知识+实例) 23.垃圾回收机制,继承

柯里化函数

  • 把一个接收多个参数的单个函数改成接收单个参数多个参数(化繁为简)
  • 每一次函数调用结束之后 会返回一个新的函数(闭包)
  • 作用:
    1. 简化参数 参数复用
    2. 延迟调用
  • 缺点:

设计模式

  • 单例模式
    • 解决类或者构造函数创建出来的实例只有一份
    • 实现:提供一个函数 只要调用这个函数返回一个实例
    • 实例放在全局存储
    • 使用闭包
  • 订阅发布模式(观察者)
    • 解决的是一个对象变化所有依赖这个对象的数据都会相应的变化
    • 实现:类
      • 属性: message
        • {类型: [行为,行为]}
      • 方法: 订阅on 发布emit
    • v2 v3

垃圾回收机制(GC)

含义: js在运行的时候会自动回收一些废弃数据的内存空间(自动回收)

  • 垃圾回收机制运行时机:在程序运行完成之后 所有线程闲置的时候会触发垃圾回收机制

  • 垃圾回收机制的算法

    1. 引用计数法
      • 在创建一个数据的时候 该数据引用次数默认为1
      • 当我们把这个数据赋值给其他的变量的时候 该数据引用次数会+1
      • 当我们把用到某个数据变量置为空 该数据引用次数会-1
      • 一直到数据引用次数为0的时候 垃圾回收机制就会回收该数据的存储空间
    2. 引用计数法会遇到一个循环引用的问题
    3. 标记-清除法
      • 标记
        • js会将所有的数据默认为0
        • 从根对象去访问每一个对象里面的key,如果可以访问标记为1
        • 从根对象去访问每一个对象里面的key,如果不可以访问标记为0
      • 清除
        • 将内存里面所有的数据对象都遍历一遍 看这个对象上面的标识 如果标识是0 清除这个对象;如果标识是1 保留这个对象
  • 垃圾回收机制对于我们写代码的影响

    1. 复杂数据如果不用的时候 自己手动清空
    2. 尽量减少把数据挂载到全局
    3. 定时器都是挂载到全局 定时器不用的时候记得清除 vue组件里面的定时器在组件销毁的时候记得清除
    4. 不用的事件处理函数要清空
  • 什么是垃圾回收机制

  • 垃圾回收机制算法有哪些

  • 垃圾回收机制有哪些影响

继承(重灾区)

  • 面向对象的三大特征

    1. 封装
    2. 继承
    3. 多态
  • 继承

    • 含义:子类可以直接使用父类的属性和方法 不需要自己实现
      • es5是没有类这个概念 用构造函数+原型模拟类的功能(面试着重关注点)
      • es6提出类的概念 只是一个语法糖(关键字 extends)
  • es5实现继承

    • 准备父类 添加属性 原型添加方法
    • 借助构造函数实现继承父类的属性
      • 做法: 在子类构造函数里面调用父类的构造函数 并且利用call或者apply同时修改父类构造函数里面this的指向,指向到子类的实例
    • 借助原型实现继承父类原型的方法
      • 做法: 将子类构造函数原型指向父类的某个实例
    • 组合继承
      • 借助构造函数+借助原型
      • 既可以继承父类的属性也可以继承父类原型上面的方法
    • construcotr属性
      • 每一个实例访问constructor得到就是它的构造函数
  • es6实现继承

    • 准备父类和子类
  • 继承关系

    • js继承关系都是单向继承,父类方法变化 子类会改变;但是子类变化,父类不会变化
  • 原型

    • 三句话
  • 原型链

    • 一个对象访问属性和方法的时候会优先在自身查找,自身有就用自身的
    • 自身没有就会自动往__proto__上面查找 __proto__有就使用
    • __proto__没有会继续往下一级的__proto__上面查找 下一级有就使用
    • 下一级没有就继续往下一查找,一直找到原型链最顶层是null
  • js实现继承的方式有哪些?

实例

(以下代码均为课程实例)

(1)引用计数法

 <script>
        // 计算一个变量(引用的数据类型)使用次数
        // 当我们一个变量创建的时候 引用就产生了 obj引用次数+1
        var obj = {a:1}
        // 当我们把这个变量赋值给另一个变量   obj引用次数+2
        // 复杂数据类型赋值方式是引用传递
        var obj2 = obj
        // 新增一个obj3的应用 obj3引用次数+1
        var obj3 = {...obj}
        // 当我们把某一个变量置为空null obj引用次数+1
        obj = 1
        console.log(obj2.a)
        // obj引用次数 0
        obj2 = 1

        // 此段代码运行之后才会触发垃圾回收机制
    </script>

(2)循环引用


   <script>
      function test() {
        let A = new Object();  // A对象引用次数+1
        let B = new Object();  // B对象引用次数+1
        A.pointer = B; // B +2
        B.pointer = A; // A +2

        A.pointer = null
        B.pointer = null
      }
      // 本来函数test执行结束之后  执行空间会被销毁
      // 
      test();
    </script>

(3)标记清除法


    <script>
        // 标记 从根对象开始  跟对象就是全局对象
        //person{a:1,b:2}总共引用次数是多少
        // person 可以被访问  标记为可达
        var person = {
            a:1,
            b:2
        }
        // obj 可以被访问  标记为可达
        var obj = {
            a: person
        }
        // obj2 可以被访问  标记为可达
        var obj2 = {
            a: obj // 不可达
        }

        function fn(data){
            // p也是可达
            let p = data
            // s也是可达
            let s = {
                a: p
            }
        }
        fn(obj2)
        obj = null
        {a:1}
        var data = {
            a: obj2, // 可达
            b: obj, // 不可达
            c: person // 可达
        }
        

    </script>

(4)垃圾回收机制影响

<body>
    <div class="box">
        Lorem ipsum dolor, sit amet consectetur adipisicing elit. Ipsam placeat inventore autem excepturi unde commodi incidunt, illum quia repellendus porro nemo architecto sint numquam exercitationem libero nobis vero dolor ipsum?
    </div>
    <script>
        function A(){
            var a = 1
            return function B(){
                a++
                console.log(a)
            }
        }
        let o = A() // A执行空间不会被销毁
        // o()
        // o()
        // o()
        // o()
        // o = null // 手动去清除o的引用关系 触发垃圾回收机制
        // let o1 = A() // 又创建了一个
        
        // function get(){
        //     let sum = 10
        //     sum++
        // }
        // get()
        // console.log(sum)


        var box = document.querySelector('.box')
        function A(){
            console.log('do A..')
        }
        function B(){
            console.log('do B..')
        }
        box.addEventListener('click', A)
        box.addEventListener('click', B)
        setTimeout(()=>{
            box.removeEventListener('click', B)
            B=null
        }, 5000)
    </script>

</body>

(5)es5继承-继承属性

   <script>
        /* 借助构造函数实现继承父类的属性 */
        // 准备父类
        function Person(){
            // 添加属性
            console.log('Person被调用了')
            this.username = 'jack'
            this.age = 18
        }
        // 添加方法
        Person.prototype.sayHi = function(){
            console.log('person hi...')
        }
        // 创建父类的实例
        var p = new Person()
        console.log(p)

        // 准备子类
        // 让Student称为Person子类
        function Student(){
            // 本身自己没有添加username属性
            console.log('Student被调用了')
            // 在子类的构造函数内部手动调用父类的构造函数
            // 调用父类构造函数同时 修改父类构造函数内部this指向 指向到子类的实例
            // console.log(this)
            // this.age = 18
            Person.call(this)
        }
        // 创建子类的实例 希望创建出来的实例由username属性
        var s = new Student()
        console.log(s)
    </script>

(6)es5继承-继承父类原型方法-优化

    <script>
        // 父类
        function Person(){
        }
        // 添加方法
        Person.prototype.sayHi = function(){
            console.log('person hi...')
        }
        Person.prototype.walk = function(){
            console.log('person walk...')
        }
        // 创建父类的实例
        // const p = new Person()
        // console.log(p)
        // p.sayHi()
        // p.walk()
        // 准备子类
        function Student(){
        }
        // 希望子类构造函数prototype上面有sayHi和walk
        // 将子类构造函数prototype指向到父类的某个实例
        Student.prototype = new Person()
        const s = new Student()
        console.log(s)
        s.sayHi()
        s.walk()

        // 给子类原型新增一个方法
        Student.prototype.study = function(){
            console.log('student study...')
        }

        const p2 = new Person()
        console.log(p2)
        // p2.study()

        // 给Person的原型添加方法
        Person.prototype.eat = function(){
            console.log('person eat...')
        }
        const s2 = new Student()
        console.log(s2)
        s2.eat()
    </script>

(6)es5继承-继承父类原型方法

   <script>
        // 父类
        function Person(){
        }
        // 添加方法
        Person.prototype.sayHi = function(){
            console.log('person hi...')
        }
        Person.prototype.walk = function(){
            console.log('person walk...')
        }
        // 创建父类的实例
        const p = new Person()
        console.log(p)
        p.sayHi()
        p.walk()
        // 准备子类
        function Student(){
        }
        // 希望子类构造函数prototype上面有sayHi和walk
        // 把父类的构造函数的prototype赋值给子类
        Student.prototype = Person.prototype
        const s = new Student()
        console.log(s)
        s.sayHi()
        s.walk()
    </script>

(6)es5继承-继承父类原型方法问题

    <script>
        // 父类
        function Person(){
        }
        // 添加方法
        Person.prototype.sayHi = function(){
            console.log('person hi...')
        }
        Person.prototype.walk = function(){
            console.log('person walk...')
        }
        // 创建父类的实例
        const p = new Person()
        console.log(p)
        p.sayHi()
        p.walk()
        // 准备子类
        function Student(){
        }
        // 希望子类构造函数prototype上面有sayHi和walk
        // 把父类的构造函数的prototype赋值给子类
        // 此处就是引用传递
        Student.prototype = Person.prototype

        // 给子类原型上面添加一个方法
        Student.prototype.study = function(){
            console.log('student study...')
        }
        const s = new Student()
        console.log(s)
        s.sayHi()
        s.walk()
        s.study()
        // 父类实例上面也出现子类的原型方法
        const p2 = new Person()
        console.log(p2)
        p2.study()
        // 父类原型上面添加一个方法
        Person.prototype.eat = function(){
            console.log('person eat...')
        }

        const s2 = new Student()
        console.log(s2)
    </script>

(7)原型链

    <script>
        function Aniaml(){

        }
        function Person(){

        }
        Person.prototype = new Aniaml()
        Person.prototype.sayHi = function(){
            console.log('sayHi..')
        }
        function Student(){
            // this.sayHi = function(){
            //     console.log('子类自身属性')
            // }
        }
        const p = new Person()
        console.log(p)
        console.log(p.__proto__)
        Student.prototype = p

        const  s = new Student()
        // console.log(s)
        // console.log(s.__proto__)
        // console.log(Student.prototype = s.__proto__)
        // // s.__proto__ == Student.prototype == p
        // // s.__proto__.__proto__ === p.__proto__ === Person.prototype
        // console.log(s.__proto__ === p)
        // console.log(p.__proto__ === Person.prototype)
        // console.log(s.__proto__.__proto__)
        // s.__proto__.__proto__.sayHi()
        // s.sayHi()
        console.log(s.__proto__)
        console.log(s.__proto__ === Student.prototype)
        console.log(s.__proto__.__proto__)
        console.log(s.__proto__.__proto__ === Person.prototype)
        console.log(s.__proto__.__proto__.__proto__)
        console.log(s.__proto__.__proto__.__proto__ === Aniaml.prototype)
        console.log(s.__proto__.__proto__.__proto__.__proto__)
        console.log(s.__proto__.__proto__.__proto__.__proto__ === Object.prototype)
        console.log(s.__proto__.__proto__.__proto__.__proto__.__proto__)

    </script>

(8)组合继承

    <script>
        function Person(username,age){
            // 添加属性
            this.age = age
            this.username = username
        }
        // 添加方法
        Person.prototype.sayHi = function(){
            console.log('person hi...')
        }
        Person.prototype.walk = function(){
            console.log('person walk...')
        }
        // 准备子类
        function Student(username, age){
            // Person.call(this,username, age)
            Person.apply(this,[username, age])
        }
        // 此处赋值的时候 把constructor覆盖了
        // {constructor: Student}
        // {username:undefined,age:undefined}
        Student.prototype = new Person()
        // 修改Student的constructor属性
        Student.prototype.constructor = Student
        const s = new Student('jack', 18)
        console.log(s)
        console.log(s.username)
        s.sayHi()

        // 每一个实例 访问constructor属性 得到是构造函数
        console.log(s.constructor)
    </script>

(9)es6继承

    <script>
        // 父类一般行公共的属性和方法
        class Person{
            constructor(username, age){
                this.username = username
                this.age = age
            }
            sayHi(){
                console.log('sayHi方法')
            }
            walk(){
                console.log('walk方法')
            }
        }
       
        // 子类还需要实现自己特有的属性和方法
        class Student extends Person{
            constructor(username, age, number){
                // 在子类构造函数访问this属性之前 调用父类的构造函数
                // super代表父类的构造函数名称
                super(username,age)
                this.studyNo = number
            }
            // 子类特有的方法
            study(){
                console.log('学习')
            }
        }
        const s = new Student('jack', 18, '10089')
        console.log(s)
        class Teacher extends Person{
            constructor(username, age, number){
                super(username,age)
                this.workNo = number
            }
            // 重写父类的方法
            sayHi(){
                console.log('teacher重写sayHi')
            }
        }
        const t = new Teacher('tom', 28, '11111')
        console.log(t)
        t.sayHi()

        const p = new Person('jerry', 18)
        console.log(p)
        
    </script>

(10)作业1-es5实现

    <script>
        /* 
            实现一个父类,父类Car
                + 属性
                    - brandName
                    - wheel
                    - generator
                + 方法
                    - run
                    - stop
            实现几个子类
                + BWM
                    - 属性:sat 真皮座椅
                    - 方法: 一键启动   
                + BenChi
                    - 属性:全景天窗
                    - 方法: 防抱死 重写stop方法
            es5
            es6
                
        */

        //es5方法


        function Car(brandName, wheel, generator) {
            //给父类添加属性
            this.brandName = brandName
            this.wheel = wheel
            this.generator = generator
        }
        Car.prototype.run = function () {
            console.log('run被调用了')
        }
        Car.prototype.stop = function () {
            console.log('stop被调用了')
        }
        var c = new Car('大众', '四轮', '三缸发动机')
        console.log(c)
        c.run()
        c.stop()


        function BMW(sat, brandName, wheel, generator) {
            this.sat = sat
            Car.apply(this, [brandName, wheel, generator])
        }
        BMW.prototype.ABS = function () {
            console.log('ABS被调用')

        }

        

        BMW.prototype = new Car()
        BMW.prototype.constructor = BMW
        var b = new BMW('真皮座椅','宝马','四轮','六缸发动机')
        console.log(b)
        b.run()
        b.stop()
        








        function BenChi(sat, brandName, wheel, generator) {
            this.sat = sat
            Car.apply(this, [brandName, wheel, generator])
        }
        BenChi.prototype.toRun = function () {
            console.log('toRun被调用')

        }

        

        BenChi.prototype = new Car()
        BenChi.prototype.constructor = BenChi
        var b = new BenChi('狗皮座椅','奔驰','四轮','四缸发动机')
        console.log(b)
        b.run()
        b.stop()


        BenChi.prototype.stop1 = function(){
            console.log('stop1方法调用')
        }
        
        // c.stop1()
    </script>

(11)作业2-es6实现

    <script>
        /* 
            实现一个父类,父类Car
                + 属性
                    - brandName
                    - wheel
                    - generator
                + 方法
                    - run
                    - stop
            实现几个子类
                + BWM
                    - 属性:sat 真皮座椅
                    - 方法: 一键启动   
                + BenChi
                    - 属性:全景天窗
                    - 方法: 防抱死 重写stop方法
            es5
            es6
        */
        
        class Car{
            constructor(brandName, wheel, generator){
                this.brandName = brandName;
                this.wheel = wheel;
                this.generator = generator;
            }
            run(){
                console.log('run...');
            }
            stop(){
                console.log('stop...');
            }
        }
        const car = new Car('比亚迪', '四个轮子', '四缸发动机');
        console.log(car);
        car.run();
        car.stop();

        class BMW extends Car{
            constructor(brandName, wheel, generator, leatherSeat){
                super(brandName, wheel, generator);
                this.leatherSeat = leatherSeat;
            }
            start(){
                console.log('start...');
            }
        }
        const bmw = new BMW('宝马', '五个轮子', '五缸发动机', '真皮座椅');
        console.log(bmw);
        bmw.run();
        bmw.stop();
        bmw.start();

        class BenChi extends Car{ 
            constructor(brandName, wheel, generator, skylight){
                super(brandName, wheel, generator);
                this.skylight = skylight;
            }
            stop(){
                console.log('obs改写stop...');
            }
        }
        const benchi = new BenChi('奔驰', '六个轮子', '六缸发动机', '全景天窗');
        console.log(benchi);
        benchi.run();
        benchi.stop();
    </script>
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不二哈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值