行内JavaScript与前两种方式不同,只需要将JavaScript代码写入HTML标签的属性中,不需要使用单独的
继承方式-零基础JavaScript从入门到精通
JavaScript基于原型链继承,在实际使用中除了使用原型链继承外,还有构造继承、实例继承、拷贝继承、组合继承、寄生继承等多种方式。
1.原型继承
12.6.2.html使用原型继承在不同对象之间传递属性和方法,如下所示。
动手写12.6.2
执行12.6.2.html,输出结果到网页,如下图所示。
图12.6.2 原型继承
采用原型继承的方式简单、容易理解,但有以下缺点:
◇ 所有子类共享的Child.prototype是一个父类的实例。
◇ 构造子类实例时,没有向父类构造函数传参,导致父类实例的部分属性不能传递给子类实例。
◇ 无法实现多继承。
2.构造继承
12.6.3.html在构造函数内部调用父类的构造函数,继承父类构造函数内部定义的属性和方法,如下所示。
动手写12.6.3
执行12.6.3.html,输出结果到网页,如下图所示。
图12.6.3 构造继承
采用构造继承的方式避免了在多个子类实例共享父类实例,但也导致子类实例不能继承父类的原型,因此child instanceof Supper等于false。
3.实例继承
12.6.4.html在子类构造函数内部调用父类构造函数,创建父类实例对象,并设置子类构造函数内部定义的属性和方法,实现实例继承,如下所示。
动手写12.6.4
执行12.6.4.html,输出结果到网页,如下图所示。
图12.6.4 实例继承
相比于构造继承,实例继承虽然能够从父类获取原型属性和方法,但产生的问题更加严重,它修改了实例与构造函数的对应关系,导致new Child()返回的是child对象而不是Child的实例。
4.拷贝继承
将“父类”原型上所有的属性和方法赋值(拷贝)给“子类”实例对象,实现继承。
12.6.5.html使用拷贝实现继承,如下所示。
动手写12.6.5
(www.chuimin.cn)
执行12.6.5.html,输出结果到网页,如下图所示。
图12.6.5 拷贝继承
拷贝继承解决了子类实例child访问Child原型属性和方法的问题,但它与实例继承存在同样严重的问题,即修改了构造函数本应该返回的实例,导致child instanceof Child等于false,并且导致了更多的性能开销。
5.组合继承
采用原型继承和构造继承组合的方式,确保子类实例拥有不同的父类实例属性。
12.6.6.html使用组合继承,如下所示。
动手写12.6.6
执行12.6.6.html,输出结果到网页,如下图所示。
图12.6.6 组合继承
组合继承仍然有一个缺点,就是调用两次父类构造函数,在子类实例和Child.prorotype都具有父类的实例属性。访问子类实例属性时会屏蔽Child.prototype上的同名属性,目前这种继承方式较能被接受。
6.寄生组合继承
寄生组合继承就是在子类和父类之间设置空对象,实现继承。
12.6.7.html使用寄生组合继承,如下所示。
动手写12.6.7
执行12.6.7.html,输出结果到网页,如下图所示。
图12.6.7 寄生组合继承
通过中间的空白函数去掉Child.prototype上Supper的实例属性。这种方式并没有消除多余的Supper实例,反而让原型链多了一层。
7.proto继承
在单继承上,上述继承方式都没有完美解决冗余的Supper实例、instanceof不符合预期、构造函数返回其他函数的实例等问题,虽然名称不同但实现方式类似。只有修改Child.prototype的原型,才能解决上述问题。
12.6.8.html修改子类的__proto__属性实现继承,如下所示。
动手写12.6.8
执行12.6.8.html,输出结果到网页,如下图所示。
图12.6.8 proto继承
在Child构造函数中,调用Supper构造函数不是必须的,但需要具备这种能力。