JS面向对象编程之 - 继承

简述

开始前先定一个父类用于继承

function Persion(name){
    this.name = name || 'Persion';
    this.opt = {
      a: 1,
      b: 2
    };

    this.eat = function(){
        console.log(this.name + '..eating..')
    }
}
Persion.prototype.getName = function(){
    return this.name;
}

1. 原型链继承

核心:将父类的实例作为子类的原型

function Author() {}
Author.prototype = new Persion();
Author.prototype.constructor = Author;


var xxy = new Author()

console.log(xxy.name) // Persion
xxy.eat() // Persion eating
console.log(xxy.getName()) // Persion
console.log(xxy instanceof Persion); // true
console.log(xxy instanceof Author); // true

优点:

  1. 实例是子类的实例,也是父类的实例
  2. 父类新增原型方法/原型属性,子类都能访问到

缺点:

  1. 无法实现多继承
  2. 来自原型对象的引用属性是所有实例共享的
var db = new Author()

xxy.opt.a = 22

console.log(xxy.opt.a) // 22
console.log(db.opt) //22
  1. 创建子类实例时,无法向父类构造函数传参

2. 构造继承

核心:使用父类的构造函数来增强子类实例,等于复制父类的实例属性给子类

function Author(){
    Persion.call(this, name);
}

var xxy = new Author()

console.log(xxy instanceof Persion); // false
console.log(xxy instanceof Author); // true

优点:

  1. 解决了原型链继承的缺点2
  2. 创建子类实例时,可以向父类传递参数
  3. 可以实现多继承(call多个父类对象)

缺点:

  1. 实例并不是父类的实例,只是子类的实例
  2. 只能继承父类的实例属性和方法,不能继承原型属性/方法
  3. 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

3. 实例继承

核心:为父类实例添加新特性,作为子类实例返回

function Author(name){
    var instance = new Persion(name)

    return instance
}

var xxy = new Author()

console.log(xxy instanceof Persion); // true
console.log(xxy instanceof Author); // false

优点:

  1. 不限调用方式

缺点:

  1. 不支持多继承
  2. 实例是父类的实例,不是子类的实例

4. 拷贝继承

function Author(name){
    var instance = new Persion(name)
    for (var p in instance) {
        Author.prototype[p] = instance[p];
    }
}

var xxy = new Author('XXY')

console.log(xxy instanceof Persion); // true
console.log(xxy instanceof Author); // false

优点:

  1. 支持多继承

缺点:

  1. 效率较低,内存占用高(因为要拷贝父类的属性)
  2. 无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)

5. 组合继承

核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用

function Author(name, books){
    Persion.call(this, name);
    this.books = books;
}
Author.prototype = new Persion();
Author.prototype.constructor = Author;

Author.prototype.getBooks = function(){
    return this.books;
}

var xxy = new Author('XXY')
  • 使用callapply方法,将父对象的构造函数绑定在子对象上。
  • 任何一个prototype对象都有一个constructor属性,指向它的构造函数,第17行的目的是为了防止继承链的紊乱。

优点:

  1. 弥补了构造继承的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法
  2. 既是子类的实例,也是父类的实例
  3. 不存在引用属性共享问题
  4. 可传参
  5. 函数可复用

缺点:

  1. 调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)

6. 寄生组合继承

核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点

提示:推荐使用

function Author(name){
    Persion.call(this, name);
}

(function(){
    // 创建一个没有实例方法的类
    var Super = function(){};
    Super.prototype = Persion.prototype;
    //将实例作为子类的原型
    Author.prototype = new Super();
    Author.prototype.constructor = Author;
})();


var xxy = new Author('XXY')

为了简化类的声明,可以把派生子类的整个过程包装在一个extend的函数中。

function extend(subClass, superClass) {
    var F = function(){};
    F.prototype = superClass.prototype;
    subClass.prototype = new F();
    subClass.prototype.constructor = subClass;
}

但是,这样存在一个问题。就是同名函数会被复写,可以添加一个superclass属性来解决这个问题。

function extend(subClass, superClass) {
    var F = function() {};
    F.prototype = superClass.prototype;
    subClass.prototype = new F();
    subClass.prototype.constructor = subClass;

    subClass.superclass = superClass.prototype; // 添加superclass属性
    if(superClass.prototype.constructor == Object.prototype.constructor) {
        superClass.prototype.constructor = superClass;
    }
}

function Author(name, books){
    Author.superclass.constructor.call(this, name);
    this.books = books;
}
extend(Author, Persion);
Author.prototype.getBooks = function(){
    return this.books;
}

有了superclass属性,子类便可定义跟父类重名的原型方法,使用其原有函数的逻辑。

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

推荐阅读更多精彩内容

  • 一.子类的原型对象--类式继承 类式继承就是将子类的原型_ proto_指向父类的原型对象,这个新创建的对象可以访...
    夏liao夏天阅读 275评论 0 0
  •   面向对象(Object-Oriented,OO)的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意...
    霜天晓阅读 2,076评论 0 6
  • 博客内容:什么是面向对象为什么要面向对象面向对象编程的特性和原则理解对象属性创建对象继承 什么是面向对象 面向对象...
    _Dot912阅读 1,371评论 3 12
  • 求欢天喜地,但愿两情安稳。 世情人情,不及东风恶。 无奈收拾残局,心事怕说破,人瘦桃花落。 不许海誓山盟,更怕甜蜜...
    躲进小楼阅读 300评论 0 0
  • 前情提要:恋你十年,未曾改变(五十六) 我本来想假借志远婚礼的名义让坤在婚礼前一天住在我这,毕竟坤妈重病这段时间...
    lemoney阅读 459评论 7 3