工厂函数

一、享元模式

通过将可重复使用的方法与属性保存在一个代理对象中, 进而节省一些系统资源, 特别是应用中存在大量类型相同的实例时, 使用享元模式可以明显提升系统性能并有效减少内存损耗。

假如需要创建很多类似于4399小游戏中的小怪, 每个小怪的包含了生命值、攻击力、速度、如何攻击等属性与方法, 那么这样的一个对象应该这样创建 :

let enemyPrototype = {
    name: 'wolf',
    position: { x: 0, y: 0 },
    setPosition: function setPosition(x, y) {
        this.position = {
            x: x, y: y
        };
        return this;
    },
    health: 20,
    bite: function bite(){},
    evade: function evade(){}
},
    wolf1 = Object.create(enemyPrototype),
    wolf2 = Object.create(enemyPrototype);

把实例级别的数据都放在原型上很少见, 更多的是把一些复用性较强的默认属性值放在原型上, 需要注意的是, 在操作数组对象这类引用类型的属性时, 需要倍加小心啊 ! 尽量做替换而不是修改 (为什么请参考 原型代理与原型克隆 这篇文章, 点我火速前往)。

二、创建对象

对象有相当一部分是构造函数生成的, 下面的例子是在对汽车进行一个简单的封装, 包括颜色、方向、油量、以及加速、减速等方法。

function Car(color, mph) {
    this.color = color || 'pink';
    this.direction = direction || 0;
    this.mph = mph || 0;

    this.gas = function gas(amount) {
        amount = amount || 10;
        this.mph += amount;
        return this;
    };
    this.brake = function brake(amount) {
        amount = amount || 10;
        this.mph = ((this.amount - amount) < 0) ? 0 : this.mph - amount;
        return this;
    };
    this.toggleParkingBrake = function toggleParkingBrake() {
        isParkingBrakeOn = !isParkingBrakeOn;
        return this;
    };
    this.isParked = function isParked() {
        return isParkingBrakeOn;
    }
}

我们实例化的方式往往是通过 new 关键字来完成。

const car = new Car('red', 100);

但是就工厂函数而言, 获取一个实例省去了 new 关键字, 创建具体实例的工作交给工厂函数本身来完成, 当它创建好一个对象后, 便返回此对象。

let carPrototype = {
    color: 'pink'
    direction: 0,
    gas: function gas(amount){
        // do something meaningful
    },
    // more attributes
},
    car = function car(options) {
        // 创建的过程中, 相同属性会被覆盖
        return Object.assign(Object.create(carPrototype), options);
    },
    myCar = car({color: 'red'});

这里先构建了一个原型, 然后又创建了 car 这个工厂函数, 它会返回一个实例对象, 最后把这个实例对象的引用给了 myCar 变量。

如果使用构造函数, 那么只能使用 new 进行实例化, 而工厂函数内部可以使用javascript 的各种构建对象的方法, 使用起来更加灵活。

使用工厂函数的好处就是无需担心忘记 new 关键字时, 属性与方法的赋值会污染全局对象。

添加新评论