学习js设计模式-开山篇(面向对象复习篇)

418 阅读4分钟

设计模式是软件开发人员在开发过程中遇到问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。学习设计模式之前我觉得很有必要先复习下面向对象, 这里直接以es6+ 语法书写

定义类

class Father {
    //构造方法
    constructor(name, age) {  
        this.name = name
        this.age = age
    }
}

上面就是一个最简单的class结构体, 我们定义了一个Father 类, 里面有个 constructor 用于创建和初始化对象。js中 一个类只能拥有 一个 constructor 每个对象的原型上都有个constructor属性 指向构造函数, 即

Father.prototype.constructor === Father

这里再说几个大家平时可能没注意的点:

  1. typeof Father === "Function"

  2. 如果没有显示声明会默认生成一个空的 constructor() {}

  3. constructor 默认返回实例对象(也就是 this)

让我们深入下第三点修改返回对象, 看下会发生什么

class Father {
    //构造方法
    constructor(...args) {  
        return {}  //这里改变了默认返回对象
    }
}

//此时大家觉得下面这个情况打印出什么, 答案滑到最右边
new Father() instanceof Father  
new Father() instanceof Object
                                                                                                                                            //第一行相当于  {} instanceof Father  所以打印出 false, 第二行相当于 {} instanceof Object 很显然 true

微信图片_20211023234015.png 可能有人猜错了, 这里我们又得牵扯出 instanceof 的定义

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

可能很多人觉得看不太懂官方定义, 我的简单技巧是 你就用它来判断 某个对象是不是属于 某一类, 举个简单例子:Array instanceof Object === true



接下来我们复习下如何定义公共方法

定义公共方法

这里需要注意class 内部方法之间不需要 逗号 隔开

class Father {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
    
    describe() {
        console.log('哇 是 林 北': this.name)  
    }
}

创建实例对象

const f1 = new Father('老马', 39)

const f2 = new Father('老羊', 41)

const f3 = new Father('老王', 37)

// 有这么多老爸, 可以少奋斗几十年了 —————— 重案组曹达华

f1.__proto__ === f2.__proto__    // __proto__ 指向构造函数的原型

继承

class Child extends Father {
    constructor(m) {
        //this.m = m  //报错, 因为子类还没继承父类this, 所以 super() 通常写在第一行
        super()  //必须调用,用来继承父类this对象 然后对其加工, 因为子类没有自己的this, 
        this.m = m //正常加工
    }
    
    write() {
        // 写一篇作文 《我的父亲》
        super.describe()   //这里super 指向 Father.prototype  然后调用父类上describe方法
    }
}

划重点

super() 相当于 Father.prototype.constructor.call(this) 虽然指向父类构造函数, 但是返回的是子类实例

静态属性、静态方法

//静态方法
class Father {

    // 这里有个贷款内容, 特地写成静态方法
    static loan() {
        //欠了几百万花呗... 不希望被实例对象知道
        
        //值得一提的是静态方法里不能用this, 切记!切记
    }
    
    //公有方法
    house() {
        //大别墅
    }
}

    
   //静态方法可以通过构造函数调用 
   Father.loan()    
   
   const f = new Father()
   f.loan()   // 报错, 静态方法不会被实例继承

类的实例属性

class Father {
    state = {
       name: '' , 
       home: {}
    }
}

class 内部 以前是不支持静态属性的, 以前写法

    Father.state = {}    //直接在方法后面拓展, 而不是在class内部

现在好像支持内部静态属性了

class Father {
    static state = { //一个人的名字和家庭一般不会换, 可写成静态属性
       name: 'aa' , 
       home: {}
    }
    
    constructor() {
        //log( Father.state )
    }
    
    `我们可以通过定义公共方法 调用或者改变 静态属性`
    
    changeState() {
        Father.state.name = "xx" 
    }
}

划重点: 静态方法是可以被子类继承的

class Father {
    //老爹会飞
    static fly() { 
        console.log('爸爸带你飞')
    }
    
    //可以申明一个与静态方法同名的公共方法, 但是不建议
    fly() {
        log('一起飞')
    }
}
class Child extends Father {
    
}
//之前这里陷入误区, 又用 new Child().fly() 了!! 上面刚说过实例是不能继承静态方法的!!!
Child.fly()  //打印出: 爸爸带你飞

这里稍微提一下,不管是静态方法,还是公共方法, 都是先找子类本身的, 找不到再向父亲要, 父亲如果找不到,再向爷爷要, 以此类推

私有属性、私有方法

经过测试,暂时好像还不能完全私有化, 但是随着前端发展, 我相信该有的都会有

class Father {
    #house = '300平米大别墅' 
    
    //调用私有属性
    look() {
        console.log(this.#house)   //实例或者子类 还是能引用到, 还是不够私有化? 
    }
    
    //定义私有方法的两种方式
    #method_1() {
    
    }
    
    #method_2 = function() {
        
    }
}

根据子类得到父类

古时候有滴血认亲, 现在科技发达了可以检验DNA, js也有自己的方法判断谁是父亲

    Object.getPrototypeOf(Child) === Father   //true
    

最后的轻语

从一本书看到人类的五种视角:
积极过去视角: 这类人总以积极心态回首往事,比较怀旧感恩
消极过去视角: 这类人经常回忆人生负面经历
享乐主义视角: 这类人活在当下,幸福感比较高
宿 命 论视角: 这类人认为一切都是命中注定,比较听话顺从,忍耐力较高
未 来 视 角: 这类人比较有前瞻性,为了未来舍弃当下享乐, 一直为未来担心,导致幸福感不强