写给自己看的JavaScript设计模式

116 阅读3分钟

JavaScript设计模式

  1. 工厂模式

    工厂模式,适合用于创建大量相似的对象,将创建对象的步骤定义在函数中,每次传递参数调用该函数,就会在函数内生成一个新的对象,并且把该新对象返回出来

  2. 构造函数模式

    工厂模式虽然可以创建大量相似的对象,但是无法解决对象识别问题

    //构造函数模式	构造对象的函数
    function Person(name, age, job) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.sayName = function () {
            console.log(this);
            console.log(this.name);
        };
        //return this; 不需要return 系统自动完成
    }
    // 使用new关键字
    // 1. 创建一个新对象
    // 2. 将新对象的_proto_指向构造函数的prototype对象
    // 2. 将构造函数的作用域赋值新对象 this指向这个新对象
    // 3. 执行构造函数中的代码(将属性和方法赋给里this对象)
    // 4. 返回新对象 系统自动完成
    var person1 = new Person("小米", 20, "Software Engineer");
    var person2 = new Person("Greg", 23, "Teacher");
    console.log("person.constructor == Person");
    console.log(person1.constructor == Person);//true
    console.log("person instanceof Person");
    console.log(person1 instanceof Person);//true
    console.log("person instanceof Object");
    console.log(person1 instanceof Object);//true
    

    即无法像person1通过instanceof 判断是Person的实例,

  3. 原型模式

    概述:

    创建一个空执行体的函数,然后给该函数的原型对象添加共享属性和共享方法

    function Fruits() {
    }
    
    Fruits.prototype = {
        constructor: Fruits,//覆盖之后要重新指回来
        name: "香蕉",
        color: "黄色",
        sayColor() {
            console.log(this.color);
        },
        sayAdress() {
            console.log("海南");
        }
    }
    
    let banana = new Fruits("香蕉","黄色");
    banana.sayAdress();
    banana.sayColor();
    

    原型模型没有私有属性和私有方法,并不是好用,所以常常搭配构造函数模式一起用;私有属性和方法放在构造函数中,共有属性和函数放在原型中

    let desc = Object.getOwnPropertyDescriptor(Fruits.prototype, "constructor");
    console.log(desc);
    
    重构之前 constructor属性特征enumerable默认设置false

    使用原型模式常常会重构原型对象,重构之前 constructor属性特征enumerable默认设置false

    获取原型对象
    console.log(Person.prototype);
    console.log(person1.__proto__);
    console.log(Object.getPrototypeOf(person1));//返回原型对象
    console.log(Person.prototype == person1.__proto__);//true
    

    给原型对象添加属性/方法
    Person.prototype.adress = "广州";
    person1.__proto__.sayAdress = function () {
        console.log(this.adress);
    }
    person2.sayAdress();//广州
    
    删除原型对象的属性或者方法
    //删除属性/方法
    delete Person.prototype.adress;
    person2.sayAdress();//undefined
    
    属性和方法的查找机制

    该实例对象-->__proto__指向原型对象-->Object的原型对象-->undefined

    person1.hobby = "play the guitar";
    person1.__proto__.hobby = "Roller-skating";
    Object.prototype.hobby = "go fishing";
    console.log(person1.hobby);//play the guitar
    
    delete person1.hobby;
    console.log(person1.hobby);//Roller-skating
    
    delete person1.__proto__.hobby;
    console.log(person1.hobby);//go fishing
    
    delete Object.prototype.hobby;
    console.log(person1.hobby);//undefined
    

    如果在person1实例对象中找不到该属性,将往原型链上找,直到找到,否则找到null返回undefined

    判断属性是否在对象上

    对象.hasOwnProperty("属性") //true/false

    判断属性是否在对象或者对象的原型链上

    "属性" in 对象 //true/false

  4. 组合构造函数模式和原型模式

    私有属性和方法放在构造函数中,共有属性和函数放在原型中

    //添加大量方法
    function Fruits(name, color) {
        this.name = name;
        this.color = color;
    }
    console.log(Fruits.prototype);
    let fruitsProto = Fruits.prototype
    let desc = Object.getOwnPropertyDescriptor(Fruits.prototype, "constructor");
    console.log(desc);
    Fruits.prototype = {
        constructor: Fruits,
        sayColor() {
            console.log("color");
        },
        sayAdress() {
            console.log("海南");
        }
    }
    let banana = new Fruits("香蕉", "黄色");
    banana.sayAdress();
    banana.sayColor();
    
  5. 动态模式

    在构造函数动态给原型对象添加公共属性或者公共方法

    function Person(name, age) {
        this.name = name;
        this.age = age;
        if(typeof this.sayName != "function") {
            Person.prototype.sayName = function() {
                console.log(this.name);
            }
        }
    }
    
    let person1 = new Person("小米",19);
    person1.sayName();
    

    该模式不能重构原型对象,否则会丢失动态添加的属性或者方法

  6. 寄生构造函数模式

    function Host() {
        let parasite = {};
        parasite.name = "新冠肺炎";
        parasite.copy = function() {
            console.log("复制繁殖");
        }
        return parasite;
    }
    
    let covid_19 = new Host();
    covid_19.copy();
    
    console.log(covid_19);
    

    寄生构造函数模式的原型对象指向Object的原型对象

  7. 稳妥构造函数模式

    ​ 稳妥对象:实例方法不引用this;不使用new操作符调用构造函数

    function Person(name,age) {
        let obj = {};
        obj.sayName = function() {
            console.log(name+"年龄"+age+"岁");
        }
        return obj;
    }
    
    let person1 = Person("小米",20);
    person1.sayName();
    

    返回一个对象,该对象方法的执行上下文 为构造函数执行创建的作用域