JavaScript知识点回顾(二十八)——混入(三)

292 阅读2分钟

这是我参与8月更文挑战的第二十八天,活动详情查看:8月更文挑战

显式混入

由于JavaScript不会自动实现复制行为,所以我们需要手动实现复制功能。这个功能在许多的库和框架中被称为extend(),但是为了方便理解,我们称之为mixin()。

寄生继承

显式混入模式的一种变体被称为“寄生继承”,它既是显式的又是隐式的。

    //“传统的JavaScript类”Vehicle
function Vehicle(){
    this.engines = 1;
}
Vehicle.prototype.ignitions = function(){
    console.log("Turn on my engine.");
};
Vehicle.prototype.drive = function(){
    this.ignitions();
    console.log("Steering and moving forward!");
};
//“寄生类”Car
function Car(){
    //首先,car是一个Vehicle
    var car = new Vehicle();
    //然后对car进行定制
    car.wheels = 4;
    //保存到Vehicle::drive()的特殊引用
    var vehDrive = car.drive;
    //重写Vehicle::drive()
    car.drive = function(){
        vehDrive.call(this);
        console.log("Rolling on all" + this.wheels + "wheels!");
    }
    return car;
}
var myCar = new Car();
myCar.drive();
//Turning on my engine.
//Steering and moving forward!
//Rolling on all 4 wheels!

首先我们复制了一份Vehicle父类(对象)的定义,然后混入子类(对象)的定义,如果需要的话保留到父类的特殊引用,然后用这个复合对象去构建实例。

隐式混入

隐式混入和前面提到的显式伪多态很像,因此也具备同样的问题:

    var Something = {
        cool: function (){
            this.greeting = "hello world";
            this.count = this.count? this.count + 1 : 1;
        }
    };
    Something.cool();
    Something.greeting;//hello world
    Somethig.count;// 1
    var Another = {
        cool:function(){
            //隐式把Something混入Another
            Something.cool.call(this);
        }
    };
    Another.cool();
    Another.greeting;//hello world
    Another.count;//1(count不是共享状态)   

通过在构造函数调用或者方法调用中使用Something.cool.call(this),我们实际上借用了函数Something.cool()并在Another的上下文中调用了它(通过this绑定)。最终的结果是Something.cool()中的赋值操作都会应用在Another对象上而不是Something对象上。因此,我们把Something的行为“混入”到了Another中。虽然这类技术利用了this的重新绑定功能,但是Something.cool.call(this)仍然无法变成相对引用,所以仍需要小心使用。

小结

混入模式(无论是显式还是隐式)可以用来模拟类的复制行为,但是通常会产生丑陋并且脆弱的语法,比如显式伪多态(OtherObj.methodName.call(this,...)),这会让代码更加难懂并且难以维护。此外,显式混入实际上无法完全模拟类的复制行为,因为对象只能复制引用,无法复制被引用的对象或函数本身。