前端基础打卡2-面向对象编程/原型及原型链

98 阅读3分钟

记录一下前端学习笔记,每天打卡!!

目标:

必知必会: js | 布局样式 | 客户端 | 技术栈

加分项:工具(CI/CD等) 热门模块工程化

进阶:模式 实战/算法

实战项目统一模板:做完的项目都需要自己再思考下下面的模板

业务层:modules network adapter

工程化层 :webpack plugins output

基础:ci/cs util/e2e vue/react monitor

开始第二天知识学习

构造函数

  1. 函数体内的this,指向所要生成的实例
  2. 生成的对象用new来进行实例化
  3. 可以做初始化传参

追问:

  1. 如果构造函数不初始化,可以使用? - 无法正常使用
  2. 如果项目中需要使用,通常(不被外界感知)如何解决?
    let staticProps
    function Course(){
        const _isClass = this instanceof Course
        
        if(!_isClass){
            staticProps = new Course()
            return staticProps
        }else{
            return staticProps
        }
        
        this.teacher= teacher
        this.course='oob'
        this.startCourse = function (){
        }
    }
    
    // 使用
    const course = Course()
    

上述暴露出去的是实例,而将实例化的过程防止在下层不被外界感知

启发:如果写底层代码时,不需要让外界熟悉感知内部代码思想

延深:通过改进=>不多次实例化,同一个实例=>单例模式

思考:new是什么?new的原理/ mew的时候做了什么?

    function Course(teacher,course){
        this.teacher = teacher
        this.course = course
    }
    const course1 = new Course('yy','oop')
    const course2 = new Course('zz','js')
  1. 结构上,创建了一个空对象,作为返回的对象实例
  2. 属性上,将生成的对象的原型对象指向了构造函数的prototype属性
  3. 关系上,将当前实例对象赋值给了内部的this
  4. 声明上,构造函数初始化代码的执行

思考:constructor是什么?

  1. 每个对象在创建的时候,会自动拥有一个构造函数的属性constructor
  2. constructor继承自原型对象,指向了构造函数的引用=>实例获得了类的属性=>继承了类的属性

追问:使用构造函数没有问题吗?会有什么性能上的问题? 构造函数中的每一个方法和属性都 存在每一个实例中,重复挂载导致了资源浪费

如果初始化?原型对象又是什么?

  1. 构造函数:赋予一个属性prototype,该属性引用等于实例对象的__proto__;course1.proto === Course.prototype
  2. 实例对象:每一个实例对象都有一个constructor => 指向当前构造函数;course1.constructor === Course
  3. prototype是什么?

微信图片_20240131200428.png 4. 上面的问题,如何优化? 将公有属性和方法,放在原型链上

    function Course(teacher,course){
        this.teacher = teacher
    }
    Course.prototype.course = course
    const course1 = new Course('yy','oop')
    const course2 = new Course('zz','js')

继承

  1. 原型链直接继承
    function Game(){
        this.name = 'lol'
        this.skin = ['s']
    }
    Game.prototype.getName = function(){
        return this.name
    }
    // LOL类
    function LOL(){}
    LOL.prototype = new Game()
    LOL.prototype.constructor = LOL
    
    const game1 = new LOL()
    
    // 拓展
    const game2 = new LOL()
    game1.skin.push('ss')

上面原型链继承存在的问题:

  • 父类属性一旦复制给子类的原型属性,此时属性属于子类的共享属性了
  • 实例化子类实例的时候,无法像父类传参

解决方法:构造函数继承

  1. 构造函数继承:子类的构造函数内部调用父类的构造函数
    function Game(arg){
        this.name = 'lol'
        this.skin = ['s']
    }
    Game.prototype.getName = function(){
        return this.name
    }
    // LOL类
    function LOL(arg){
        Game.call(this,arg)
    }
    const game3 = new LOL('arg')

存在问题: 无法继承原型链上共享的方法

  1. 组合继承
    function Game(arg){
        this.name = 'lol'
        this.skin = ['s']
    }
    Game.prototype.getName = function(){
        return this.name
    }
    // LOL类
    function LOL(arg){
        Game.call(this,arg)
    }
    LOL.prototype = new Game()
    LOL.prototype.constructor = LOL
    const game4 = new LOL('arg')

追问:组合继承有什么问题?问题在于:无论在何种场景下,都会调用两次父类构造函数=>寄生组合继承

  1. 寄生组合继承,原生继承方法比较完美的方式
    function Game(arg){
        this.name = 'lol'
        this.skin = ['s']
    }
    Game.prototype.getName = function(){
        return this.name
    }
    // LOL类
    function LOL(arg){
        Game.call(this,arg)
    }
    LOL.prototype = Object.create(Game.prototype)
    LOL.prototype.constructor = LOL

追问:如何实现多重继承本质是原型属性的合并

    function Game(arg){
        this.name = 'lol'
        this.skin = ['s']
    }
    Game.prototype.getName = function(){
        return this.name
    }
    function Store(arg){
        this.shop = 'steam'
    }
    Store.prototype.getPlatform = function(){
        return this.shop
    }
    function LOL(arg){
        Game.call(this,arg)
        Store.call(this,arg)
    }
    LOL.prototype = Object.create(Game.prototype)
    Object.assign(LOL.prototype,Store.prototype)
    LOL.prototype.constructor = LOL