《javascript高级程序设计》第六章 读书笔记 之 javascript继承的6种方法

本文首发于https://segmentfault.com/a/1190000017840651
ECMAScript只支持实现继承,主要依靠原型链来实现。与实现继承对应的是接口继承,由于script中函数没有签名,所以无法实现接口继承。

一、原型链

基本思想:利用原型让一个引用类型继承另一个引用类型的属性和方法。
构造函数、原型和实例的关系:每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个纸箱原型对象的内部指针。
基本用法:

function SuperType() {
    this.property = true;
}

SuperType.prototype.getSuperValue = function () {
    return this.property;
}

function SubType() {
    this.subproperty = false;
}
// 子的原型是父的对象
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function () {
    return this.subproperty;
}
var instance = new SubType();
console.log(instance.getSuperValue()); // true

关系图:
(https://img-blog.csdnimg.cn/20190222110908522.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80NDU0MTQ5MA==,size_16,color_FFFFFF,t_70)
但实际上,SuperType也有自己的原型,就是Object,这个原型是默认的。
所有函数的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype。
所以完整的关系图应该是
构造函数与原型间的关系
使用原型能够做到继承,但实际中并不单独使用原型链来实现继承,原因如下:
1、对于不需要‘父亲’的私有属性的继承:我们知道原型来创建对象,使得所有的实例都拥有这些共享的属性和方法,我们在使用原型链来继承最主要的是SubType的原型变为SuperType的实例对象,那么本来是Super实例私有的属性property,且处于SubType的原型中成为SubType实例的共享属性。
2、对于需要‘父亲‘私有属性的继承:同一,我们知道会继承父亲的私有属性,但我们无法通过传入参数到’父亲‘的构造函数来实现属性特有值的目的。
鉴于以上我们开始使用第二种继承方式。

二、借用构造函数(伪造对象、经典继承)

基本思想:在子类型构造函数的内部调用超类型构造函数

function SuperType() {
    this.colors = ['red', 'yellow', 'black'];
}

SuperType.prototype.getColor = function () {
    return this.colors;
}

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

var instance1 = new SubType();
instance1.colors.push('pink'); // ['red', 'yellow', 'black','pink']
console.log(instance1.colors);
var instance2 = new SubType();
console.log(instance2.colors); // ['red', 'yellow', 'black']
console.log(instance2 instanceof SuperType); // false
console.log(instance2.getColor()); // instance2.getColor is not a function

此方法是在子类型中调用了超(父)类型的构造函数,使构造函数中的属性初始化了。
继承的是超类型中构造函数中的属性,如上继承了colors属性,但没有继承SuperType原型中的getcolor方法。
使用此方法,我们还可以传递参数对属性进行初始化

function SuperType(age) {
    this.age=age;
}

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

var instance1 = new SubType();
console.log(instance1.age); // 18

如果需要确保SuperType构造函数不会重写子类型的属性,可以在调用超类型构造函数后,再添加应该在子类型定义的属性。
缺点:
1、超类型的原型不可见
2、所有属性方法都必须写在构造函数中,所有类型都只能使用构造函数模式创建

三、组合继承(伪经典继承,类式继承)

将原型链和借用构造函数的技术组合到一块。
思想:使用原型链实现对原型属性和方法的继承,借用构造函数实现对实例属性的继承。

function SuperType(age) {
    this.age = age;
}

SuperType.prototype.getAge = function () {
    return this.age;
}

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

SubType.prototype = new SuperType(20);
var instance1 = new SubType(18);
console.log(instance1.age); // 18
console.log(instance1.getAge()); // 18
console.log(instance1.__proto__.age); // 20
var instance2 = new SubType(17);
instance2.__proto__.age=55;
console.log(instance1.__proto__.age); // 55
console.log(instance2.__proto__.age); // 55

我们可以看到,实际上instance1和instance2的原型上仍然存在属于SuperType的实例属性的属性。只是instance1和instance2有了各自的age属性,不会再往原型上找。
instanceof和isPrototypeOf()也能够用于识别基于组合继承创建的对象。
组合继承避免了原型链和借用构造函数的缺陷并融合了两者的有点,成为js中最常用的继承模式。

四、原型式继承

思想:借助原型可以基于已有的对象创建新的对象,同时还不必因此创建自定义类型。

function object(o) {
    function F() {
    };
    F.prototype = o;
    return new F();

}

var person = {
    name: 'linda',
    friends: ['lily', 'shirley']
};
var antherPerson = object(person);
antherPerson.friends.push('tom');
console.log(antherPerson.name); // linda
console.log(antherPerson.friends); // ['lily', 'shirley', 'tom]

这个方法和原型方法原理一样,只不过把子类型的原型设置成超类型的实例对象包含在方法object中。
ECMAScript5中新增了object.create()方法来规范原型式继承(作用与上述object函数作用类似),第一个参数是想要继承的超类型的实例对象,第二个参数是子类型所具有的属性。

var person={
    name:'lily',
    age:12
}
var anotherPerson=Object.create(person,{name:{value:'linda'}});
console.log(anotherPerson.name); // 'linda'

第二个参数的写法必须如上的格式。
支持Object.create()方法的浏览器有ie9+,Firefox4.+、Safari5+、Opera12+和Chrome

五、寄生式继承

思想:与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真的是它做了所有工作一样返回对象。
代码:

function object(o){
    function F(){}
    F.prototype=o;
    return new F();
}
var person = {
    name: 'lily',
    age: 12
}
function createAnotherPerson(original){
    var clone=object(original);
    clone.sayHi=function(){
        console.log('hi');
    }
    return clone;
}
var anotherPerson =createAnotherPerson(person);
anotherPerson.sayHi(); // 'hi'
console.log(anotherPerson.name); // 'linda'

六、寄生组合式继承

组合继承是js最常用的继承模式,可以结合不同的模式的优点,但组合继承,每次都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数内部。
上述造成的结果是子类型实例中有两组超类型的构造函数中定义的属性,一组在子类型的实例中,一组在子类型实例的原型中。寄生组合式继承可以解决上述缺点。

function Super(name) {
    this.name = name;
}

Super.prototype.sayName = function () {
    console.log(this.name);
}

function Sub(age) {
    Super.call(this, 'linda');
    this.age = age;
}

Sub.prototype = new Super();
Sub.constructor = Sub;
var type=new Sub();
type.sayName(); // 'linda'
console.log(type.name); // 'linda'
console.log(type.__proto__.name); // undefined

思想:借用构造函数来继承属性,借用原型链来继承方法。即继承超类型的原型,然后再将结果指定给子类型的原型。
封装一下即:

function Super(name) {
    this.name = name;
}

Super.prototype.sayName = function () {
    console.log(this.name);
}

function Sub(age) {
    Super.call(this, 'linda');
    this.age = age;
}

function object(o) {
    function F() {
    }

    F.prototype = o;
    return new F();
}

function inheritPrototype(subType, superType) {
    var prototype = object(superType.prototype); // 创建对象
    prototype.constructor = subType; // 增强对象
    subType.prototype = prototype; // 指定对象
}
inheritPrototype(Sub, Super);
var type = new Sub();
type.sayName(); // 'linda'
console.log(type.name); // 'linda'
console.log(type.__proto__.name); // undefined

这个模式的优点体现在
1、只调用了一次Super构造函数,高效率
2、避免了在Sub.prototype上面创建不必要的多余的属性
3、原型链保持不变

开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip毕设新项目-基于Java开发的智慧养老院信息管理系统源码+数据库(含vue前端源码).zip
综合小区管理系统管理系统按照操作主体分为管理员和用户。管理员的功能包括报修管理、车位管理、车位分配管理、出入管理、字典管理、房屋管理、物业费缴纳管理、公告管理、物业人员投诉管理、我的私信管理、物业人员管理、用户管理、管理员管理。用户的功能包括管理部门以及部门岗位信息,管理招聘信息,培训信息,薪资信息等。该系统采用了Mysql数据库,Java语言,Spring Boot框架等技术进行编程实现。 综合小区管理系统管理系统可以提高综合小区管理系统信息管理问题的解决效率,优化综合小区管理系统信息处理流程,保证综合小区管理系统信息数据的安全,它是一个非常可靠,非常安全的应用程序。 管理员权限操作的功能包括管理公告,管理综合小区管理系统信息,包括出入管理,报修管理,报修管理,物业费缴纳等,可以管理操作员。 出入管理界面,管理员在出入管理界面中可以对界面中显示,可以对招聘信息的招聘状态进行查看,可以添加新的招聘信息等。报修管理界面,管理员在报修管理界面中查看奖罚类信息,奖罚描述信息,新增奖惩信息等。车位管理界面,管理员在车位管理界面中新增。公告管理界面,管理员在公告管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值