乐趣区

JavaScript中的常用继承

现在有一个自定义对象 Animal,

    function Animal(name) {this.name=name}
    Animal.prototype.getName=function () {console.log(this.name);
    }

想让对象 Dog 来继承 Animal 的所有属性和方法,常用的继承方式有:

1. 组合继承

        function Dog(name, color) {
            // 继承父类的实例属性
            Animal.call(this, name);// 显示绑定 this
            this.color = color;
        }
        // 继承父类构造函数原型属性的方法 重写原型对象
        Dog.prototype = new Animal();
        Dog.prototype.constructor = Dog;


        var d1 = new Dog('小白');
        var d2 = new Dog('小黑');
        console.log(d1.name, d2.name)
        d1.getName();
        d2.getName()

首先在 Dog 构造函数内部,通过强制改变 Animal 构造函数的 this,实现继承Animal 构造函数内部属性的目的,然后通过改变原型对象,继承 Animal 原型对象上的共享属性和方法。
但是这种方式有一个缺点,就是 Animal 函数执行了两次。

2. 寄生组合式继承

寄生组合继承被称为最友好,最完美的继承方案。

    function Dog(name) {
        // 继承父类的实例属性
        Animal.call(this,name);
    }
    // 通过 Object 的 create 方法,创建一个以 Animal.prototype 为原型对象的实例对象,赋值给 Dog.prototype
     Dog.prototype=Object.create(Animal.prototype);
     Dog.prototype.constructor=Dog;

3.js 中怎么实现多重继承呢?

js 本身是没有多重继承的概念的,但是我们可以通过一些方法实现多重继承的效果。
现在有两个构造函数 A,B

    function A() {this.type = 'A'}
    A.prototype.getType=function () {console.log(this.type);
    }
    function B() {this.name = 'B'}
    B.prototype.getName=function () {console.log(this.name);
    }

A,B 毫无关联,但是我们想让 C 同时继承 A 与 B 的方法,可以先让 C 继承 A,再将 B 上面的属性和方法复制到 C 上。

    // 寄生组合模式
    function C() {
        // 继承 A 的属性 借用构造函数
        A.call(this);  
    }
    // 继承 A 上的共享方法
    C.prototype=Object.create(A.prototype);
    C.prototype.constructor=C;

然后可以通过构造函数的方法,继承 B 的属性 B.call(this), 再将B.prototype 的属性和方法复制到 C.prototype 上即可,可以通过 Object.assign 实现复制功能,Object.assign(C.prototype,B.prototype);
最终可以写为:

    function C() {
        // 继承 A 与 B 的属性 借用构造函数
        A.call(this);
        B.call(this);
    }
    // 继承 A 上的共享方法
    C.prototype=Object.create(A.prototype);
    C.prototype.constructor=C;
    // 将 B 的原型属性上的方法 复制到 C 的原型属性上 
    Object.assign(C.prototype,B.prototype);

4.ES6 中的继承

es6 中引入了类的概念,在创建类时,可以使用 class 关键字,继承类时,可以使用 extends 关键字。

 class Dog {constructor(name, age = 2) {
                this.name = name;
                this.age = age;
            };// 分号
            // 类的方法 除了 constructor 都定义在了类的 prototype 上
            getName() {return this.name;};
            // 静态方法 静态方法不会被实例继承 通过类直接调用
            static foo() {console.log(111111111);
            }
        }

类中声明的全部是函数。
constructor 函数 中,定制实例对象的属性或方法,相当于构造函数的角色,getName 函数 是共用的方法,相当于定义在了原型对象上。

        let d = new Dog("dog", 5);
        // 通过构造函数调用静态方法
        Dog.foo();
        console.log(d.getName());

ES6 的继承机制:先创建父类实例对象,再创建子类实例对象 然后修改父类的 this,将其指向子类实例对象。子类是没有 this 的,是继承的父类的 this。所以在继承时必须通过 super 方法继承父类的属性。

    class Tidy extends Dog {constructor(name, age, color) {super(name, age);//super 调用父元素的方法 必须调用 super 不然得不到 this 
                this.color = color;
            };
            // 子类自己的方法
            getColor() {console.log(this.color);
            }
            // 重写父类的方法
            getName() {return this.name + super.getName();
                //super 相当于父类构造函数的原型属性 在此处相当于 class Dog
            }
        }

Tidy类通过 extends 继承了 Dog 类。

  let tidy = new Tidy("tidy", 2, "red");
        tidy.getColor();
        console.log(tidy.getName());
退出移动版