欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

js继承机制的实现

程序员文章站 2022-05-08 13:06:11
js继承机制的实现 1. 继承的概念 1. 说明继承的最经典的例子:几何形状。实际上,几何形状只有两种,即椭圆形(是圆形的)和多边形(具有一定数量的边)。圆是椭圆的一种,它只有一个焦点。三角形、矩形和五边形都是多边形的一种,具有不同数量的边。正方形是矩形的一种,所有的边等长。这就构成了一种完美的继承 ......

js继承机制的实现


1. 继承的概念

  1. 说明继承的最经典的例子:几何形状。实际上,几何形状只有两种,即椭圆形(是圆形的)和多边形(具有一定数量的边)。圆是椭圆的一种,它只有一个焦点。三角形、矩形和五边形都是多边形的一种,具有不同数量的边。正方形是矩形的一种,所有的边等长。这就构成了一种完美的继承关系。
  2. 在该实例中,我想阐述的并不是继承的含义,而是说明几个关键词,即:基类 子类 超类 的含义。
  3. 在该实例中,圆形是椭圆形的子类,椭圆形是圆形的超类(父类);同样,三角形(triangle)、矩形(rectangle)和五边形(pentagon)都是多边形的子类,多边形是它们的超类。
    js继承机制的实现
    ***

    2. 继承的方式

  4. 对象冒充
    // 父类 classa
    function classa(acolor){
        this.color = acolor;
        this.showcolor = function(){
            console.log(this.color);
        }
    }
    // 子类 classb
    function classb(bcolor,bname){
        this.newmethod = classa;    //  函数名classa只是指向函数的指针,所以这里是将this.newmethod也指向classa这个函数,所以函数classb就拥有了函数classa的方法和属性
        this.newmethod(bcolor);
        delete this.newmethod;  //  该操作使得实例化的对象不需要多次继承同一个函数了,因为继承一次就可以了。注意:新增的属性和方法最好都写在 删除对另一个函数引用的后面,因为如果在前面定义的话,如果父类刚好有该属性或者方法你就会把父类的属性和方法                             给覆盖掉。
        this.name = bname;
        this.sayname = function(){
            console.log(this.name);
        }
    }
    // --------------------------------------
    var obja = new classa("blue");
    var objb = new classb("red", "john");
    obja.showcolor();   //  blue
    objb.showcolor();   //  red
    objb.sayname();     //  john
  • 对象冒充还可以实现多重继承
    例如,如果存在两个类 classx 和 classy,classz 想继承这两个类,可以使用下面的代码:
    function classz() {
        this.newmethod = classx;
        this.newmethod();
        delete this.newmethod;

        this.newmethod = classy;
        this.newmethod();
        delete this.newmethod;
    }
   这里存在一个弊端,如果存在两个类 classx 和 classy 具有同名的属性或方法,classy 具有高优先级。因为它从后面的类继承。除这点小问题之外,用对象冒充实现多重继承机制轻而易举。

  1. call、apply方法(和对象冒充类似)
    call、apply这两个方法的使用方法和原理在上一个博客写了,可以去参考一下
    // call方法
    function classa(acolor){
        this.color = acolor;
        this.showcolor = function(){
            console.log(this.color);    
        }
    }
    function classb(bcolor){
        classa.call(this,bcolor);   //  这里的this指的是classb实例化的对象,让this调用函数classa,达到继承效果。第二个参数是对应classa的参数
    }
    var obja = new classa('blue');
    var objb = new classb('red');
    obja.showcolor();   //  blue
    objb.showcolor();   //  red
    function classa(acolor){
        this.color = acolor;
        this.showcolor = function(){
            console.log(this.color);    
        }
    }
    function classb(bcolor){
        // classa.apply(this,array(bcolor));
        classa.apply(this, arguments);      //  这里使用上面的或者arguments都可以,arguments代表的是实参的类数组对象
    }
    var obja = new classa('blue');
    var objb = new classb('red');
    obja.showcolor();   //  blue
    objb.showcolor();   //  red

  1. 原型链的方式
    function classa() {}

    classa.prototype.color = "blue";
    classa.prototype.saycolor = function () {
        alert(this.color);
    };

    function classb() {}

    classb.prototype = new classa();    //  这是关键

原型方式的神奇之处在于“classb.prototype = new classa()”代码行。这里,把 classb 的 prototype 属性设置成 classa 的实例。这很有意思,因为想要 classa 的所有属性和方法,但又不想逐个将它们 classb 的 prototype 属性进行手动链接。还有比把 classa 的实例赋予 prototype 属性更好的方法吗?
与对象冒充相似,子类的所有属性和方法都必须出现在 prototype 属性被赋值后,因为在它之前赋值的所有方法都会被删除。为什么?因为 prototype 属性被替换成了新对象,添加了新方法的原始对象将被销毁。所以,为 classb 类添加 name 属性和 sayname() 方法的代码如下:

    function classb() {
    }

    classb.prototype = new classa();

    classb.prototype.name = "zjy";
    classb.prototype.sayname = function () {
        alert(this.name);
    };

测试代码如下:

    var obja = new classa();
    var objb = new classb();
    obja.color = "blue";
    objb.color = "red";
    objb.name = "john";
    obja.saycolor();    //  blue
    objb.saycolor();    //  red
    objb.sayname();     //  john

  1. 原型链和对象冒充混合使用
    用对象冒充的方法继承构造函数的属性,再用原型链的方式继承构造函数的方法。
    // 父类
    function classa(acolor){//  之所以方法通过原型链来定义是因为方法多数都是对象共享的,如果放在构造函数内部的话,多个实例化对象就会产生多个同样的方法,所以为了减少这样的浪费,将方法通过原型链定义,这样即满足了共享的原则也实现了重复利用不会浪费。不管在内部定义方法还是通过原型链定义,都可以通过其他构造函数的原型链继承到。
        this.color = acolor;
    }
    classa.prototype.showcolor = function(){    //属性在构造函数内定义,方法通过原型定义
        console.log(this.color);
    }
    // 子类
    function classb(bcolor,name){
        classa.call(this,bcolor);   //  通过call()对象冒充的方式继承构造函数的属性
        this.name = name;
    }
    classb.prototype = new classa();    //  通过原型链的方式继承构造函数的方法
    classb.prototype.showname = function(){
        console.log(this.name);
    }

测试代码如下:

    var obja = new classa('blue');
    var objb = new classb('red','tom');
    obja.showcolor();   //  blue
    objb.showcolor();   //  red
    objb.showname();    //  tom

本博客参考了w3cschool相关的解释和代码,链接地址如下