JavaScript之继承

继承分为接口继承和实现继承

ECMAScript只支持实现继承,这主要是通过原型链实现的

一、原型链

构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型有一个属性指回构造函数,而实例有一个内部指针指向原型

<script>
        function SuperType() {
            this.property = true;
        }
        SuperType.prototype.getSuperValue = function() {
            return this.property;
        };

        function SubType() {
            this.subproperty = false;
        }

        //继承SuperType
        SubType.prototype = new SuperType();
        SubType.prototype.getSuperValue = function() {
            return this.subproperty;
        }
        let instance = new SubType();
        console.log(instance.getSuperValue()); //false
    </script>

以上代码定义了两个类型:SubType和SuperType。


这两个类型分别定义了一个属性和一个方法


这两个类型的主要区别是SubType通过创建SuperType的实例并将其赋给自己的原型SubType,protoype实现了SuperType的继承。

这个赋值重写了SubType最初的原型,将其替换为SuperType的实例

这意味着SuperType实例可以访问的所有属性和方法也会存在于SubType.prototype

这样实现继承之后,代码紧接着又给SubType.prototype,也就是这个SubType的实例添加了一个新方法。


最后创建了SubType的实例并调用了它继承的getSuperValue()方法

在这里插入图片描述

1、默认原型

默认情况下,所有引用原型都继承自Object,这也是通过原型链实现的
任何函数的默认原型都是一个Object的实例,这意味着这个实例有一个内部指针指向Object.prototype

在这里插入图片描述

SubType继承SuperType,而SuperType继承Object。
在调用instance.toString()时,实际上调用的是保存在Object.prototype上的方法

2、原型与继承方法

原型与实例的关系可以通过两种方式来确定。

第一种方式是使用instanceof操作符,如果一个实例的原型链中出现过相应的构造函数,则instanceof返回true

 <script>

console.log(instance instanceof Object); //true
console.log(instance instanceof SuperType); //true
console.log(instance instanceof SubType); //true

</script>

第二种方法是使用isPrototypeOf()方法

原型链中的每个原型都可以调用这个方法:只要原型链中包含这个原型,这个方法就返回true

<script>
        console.log(Object.prototype.isPrototypeOf(instance)); //true
        console.log(SuperType.prototype.isPrototypeOf(instance)); //true
        console.log(SubType.prototype.isPrototypeOf(instance)); //true
    </script>

3、关于方法

子类有时候需要覆盖父类的方法,或者增加父类没有的方法。
为此,这些方法必须在原型赋值之后再添加到原型上

  <script>
        function SuperType() {
            this.property = true;
        }
        SuperType.prototype.getSuperValue = function() {
            return this.property;
        };

        function SubType() {
            this.subproperty = false;
        }

        //继承SuperType
        SubType.prototype = new SuperType();

        //新方法
        SuperType.prototype.SuperType = function() {
            return this.subproperty;
        };

        //覆盖已有的方法
        SuperType.prototype.getSuperValue = function() {
            return false;
        }

        let instance = new SubType();
        console.log(instance.getSuperValue()); //false
    </script>

SuperType()的实例仍然会调用最初的方法。因为这个两个重写的方法都是在把原型赋值为SuperType的实例之后定义的



以对象字面量方式创建原型方法会破坏之前的原型链,因为这相当于重写了原型链

 <script>
        function SuperType() {
            this.property = true;
        }
        SuperType.prototype.getSuperValue = function() {
            return this.property;
        };

        function SubType() {
            this.subproperty = false;
        }

        //继承SuperType
        SubType.prototype = new SuperType();

        //通过对象字面量添加新方法,这会导致上一行无效
        SubType.prototype = {
            getSubValue() {
                return this.subproperty;
            },
            someOtherMethod() {
                return false;
            }
        };

        let instance = new SubType();
        console.log(instance.getSuperValue()); //报错
    </script>

在这段代码中,子类的原型在被赋值为SuperType的实例后,又被一个对象字面量覆盖了。覆盖后的原型是一个Object的实例,而不再是SuperType的实例。因此之前的原型链就断了。SuperType和SubType之间就没有关系了



4、原型链的问题

<script>
        function SuperType() {
            this.colors = ["red", "blue", "green"];
        }

        function SubType() {}
        //继承SuperType
        SubType.prototype = new SuperType();

        let instance1 = new SubType();
        instance1.colors.push("black");
        console.log(instance1.colors);

        let instance2 = new SubType();
        console.log(instance2.colors);
    </script>

在这里插入图片描述

在这个例子中,SuperType构造函数定义了一个colors属性,其中包含一个数组(引用值)。

每个SuperType的实例都会有自己的colors属性,包含自己的数组

但是,当 SubType.prototype = new SuperType();后,SubType.prototype变成了SuperType的一个实例,因此也获得了自己的colors属性

这类似于创建了SubType.prototype.colors属性,最终结果是,SubType的所有实例都会共享这个colors属性。



二、盗用构造函数

为了解决原型包含引用值导致的继承问题,一种叫"盗用构造函数的”技术开始流行起来

在子类构造函数中调用父类构造函数。

<script>
        function SuperType() {
            this.colors = ["red", "blue", "green"];
        }

        function SubType() {
            //继承SuperType
            SuperType.call(this);
        }


        let instance1 = new SubType();
        instance1.colors.push("black");
        console.log(instance1.colors);

        let instance2 = new SubType();
        console.log(instance2.colors);
    </script>

在这里插入图片描述

1、调用参数

盗用构造参数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值