面向对象编程:继承

1、类式继承

第1步、声明父类

function SuperClass() {
    this.superValue = true;
}

第2步、为父类添加共有方法

SuperClass.prototype.getSuperValue = function() {
    return this.superValue;
}

第3步、声明子类

function SubClass() {
    this.subValue = false;
}

第4步、继承父类,核心就是这一步,子类的原型指向第一个类的实例。

实例化父类的时候,实例对象复制父类构造函数内的属性和方法,并且将__proto__指向了父类的原型对象,这样就拥有了父类原型对象上的属性和方法。

将实例对象赋值给子类的原型,子类就可以访问父类的属性和方法。

SubClass.prototype = new SuperClass();

第5步、为子类添加共有方法

SubClass.prototype.getSubValue = function() {
    return this.subValue;
}

使用子类:

var instance = new SubClass();
console.log(instance.getSuperValue()); // true
console.log(instance.getSubValue()); // false

判断类与实例的关系:

console.log(instance instanceof SuperClass); // true
console.log(instance instanceof SubClass); // true
console.log(SubClass instanceof SuperClass); // false 继承关系,而不是类与实例的关系
console.log(SubClass.prototype instanceof SuperClass); // true

console.log(instance instanceof Object); // true 说明所有对象也是Object的实例

缺陷一:子类的2个实例之间会互相影响

先科普一下,值类型有:字符串、数值、布尔值、null、undefined,特征是不可变。引用类型有:对象、数组、函数,特征是可操作,可改变

当父类的共有属性是引用类型,然后一个子类实例修改了父类的属性值,那么任何指向引用类型的变量都会变,所以另一个子类实例的属性也就变了。例如:

function SuperClass() {
    this.superValue = [true];
}

function SubClass() {}
SubClass.prototype = new SuperClass();

var instance1 = new SubClass();
var instance2 = new SubClass();

console.log(instance1.superValue); // [true]
instance1.superValue.push(8);
console.log(instance1.superValue); // [true, 8]
console.log(instance2.superValue); // [true, 8]

缺陷二:子类实例无法向父类传递参数

子类实例只能向子类传递参数,没有办法向父类传递参数。不举例了。

2、构造函数继承

构造函数继承,用的是传说中的.call或.apply方法。

// 第一步、声明父类
function SuperClass(id) {
    // 引用类型共有属性,这次再看看是否解决的上面的缺陷一
    this.books = ['JS', 'HTML5', 'CSS'];
    // 值类型共有属性
    this.id = id;
}

// 第二步、父类型声明原型方法
SuperClass.prototype.showBooks = function() {
    console.log(this.books);
};

// 第三步、声明子类
function SubClass(id) {
    SuperClass.call(this, id); // 精华所在
}

// 第四步,创建两个子类实例
var instance1 = new SubClass(1);
var instance2 = new SubClass(2);

// 使用和测试
instance1.books.push('PHP');
console.log(instance1.books); // ["JS", "HTML5", "CSS", "PHP"]
console.log(instance1.id); //1
console.log(instance2.books); // ["JS", "HTML5", "CSS"]
console.log(instance2.id); // 2

instance1.showBooks(); // TypeError

注意上面代码中的“精华所在”,也就是call的用法。

可以看到子类内部就一行代码,就是SuperClass.call(this, id);,当子类实例创建的时候,SuperClass.call(this, id)就被执行了一遍。那么发生了什么呢?

第一步,将SuperClass函数的this绑定到this指向的对象上,也就是子类实例

第二步,给SuperClass函数传参,传递的参数先是SuperClass函数自带的参数,然后依次是arg1, arg2, arg3...,这里是id,也就是子类的参数id传给了父类,父类呢,又赋值给了this指向的对象(也就是子类实例)的id方法

第三步,执行SuperClass函数。这样一来,父类就传递给子类实例方法和属性。

缺陷:看到上面的TypeError吧,父类的原型方法,子类根本继承不到,非要继承则必须放到父类构造函数里,但构造函数的方法写到构造函数的里面不是最佳实践,因为各个子类实例不能共用方法,浪费内存,所以,请看下面的组合继承:

3、组合继承

类式继承,是通过实例化一个父类,然后赋值给子类的prototype来实现。

构造函数式继承,是通过在子类的构造函数作用环境里,执行了一次父类的构造函数来实现的。

综合上述两点,就构成了组合继承。

// 第一步、声明父类,跟构造函数式继承一样
function SuperClass(name) {
    // 引用类型共有属性,这次再看看是否解决的上面的缺陷一
    this.books = ['JS', 'HTML5', 'CSS'];
    // 值类型共有属性
    this.name = name;
}

// 第二步、父类声明共有方法,也跟构造函数式继承一样
SuperClass.prototype.getName = function() {
    console.log(this.name);
};

// 第三步、声明子类
function SubClass(name, time) {
    SuperClass.call(this, name); // 这依然跟构造函数式继承一样
    this.time = time; // 这跟类式继承一样
}

// 第四步,子类原型继承父类,跟类式继承一样
SubClass.prototype = new SuperClass();

// 第五步,子类原型方法,跟类式继承一样
SubClass.prototype.getTime = function() {
    console.log(this.time);
}

// 使用和测试
var instance1 = new SubClass(1, 2015);
var instance2 = new SubClass(2, 2016);

instance1.books.push('PHP');
console.log(instance1.books); // ["JS", "HTML5", "CSS", "PHP"]
console.log(instance1.name); //1
console.log(instance1.time); //2015
console.log(instance2.books); // ["JS", "HTML5", "CSS"]
console.log(instance2.time); // 2016

缺陷:父类被调用了两次,浪费内存。但是这是目前用得最多的继承实现。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容