javascript----继承模式

我是谁,我来自哪,我是谁的谁

想必大家一定在学习或者开发过程常常被JS独有的原型继承拨过不少脑弦吧,为何不迎问题而上,直面解决这些谜团,今天就来总结一下Js的认亲问题...

为开发需求选择一种合适的继承模式可以提高代码的可读性和便于排错,从而提高我们的开发效率,因而今天就来总结一下ES5之前的继承模式,ES6之后再进行补充或者另外讨论

原型链模式-----------------------------------------------所有继承模式的基础

关键词: 构造函数 原型对象 实例对象 原型对象为另一类型的实例

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(); //实例化子类对象 alert(instance.getSuperValue()); //true //调用超类的原型方法 }

原型链的问题:

  • 超类的实例属性变成了子类的原型属性,无法解决引用类型值被所有实例共享的问题.
  • 创建子类型实例时无法向超类型的构造函数中传递参数
    以上问题导致很少单独使用原型链.

借用构造函数-------------------------------------------借用超类构造函数

关键词:借用超类构造函数

function SuperType(){ this.name = name; } function SubType(){ SuperType.call(this,"LiAo"); this.age = 22; } var instance = new SubType(); alert(instance.name); //"Nicholas" alert(instance.age); // 22

借用构造函数的问题

  • 与构造函数模式一样,无法做到函数复用.
  • 另外此时没有使用原型链,所以子类无法调用超类的原型方法

组合继承----------------------------------------结合借用构造函数和原型链

关键词:
  • 借用构造函数负责实现对实例属性的继承
  • 原型链负责实现对原型属性和方法的继承(复用)
    `function SuperType(name){
    this.name = name;
    this.colors = ["red","blue","green"];
    }
    SuperType.prototype.sayName = function(){ //定义父类的原型方法
    alert(this.name);
    };
    function SubType(name,age){
    SuperType.call(this,name); //通过借用构造函数实现对实例属性的继承
    this.age = age; //子类自身的实例属性
    }

SubType.prototype = new SuperType(); //通过原型链继承超类
SubType.prototype.constructor = SubType; //恢复constructor的指向
SubType.prototype.sayAge = function(){ //定义父类独有的原型方法
alert(this.age);
};
var instance = new SubType("LiAo",22);
`
组合继承模式的优点

  • 主要融合了原型链和借用构造函数模式的优点
  • 可以用instanceof 和isPrototypeOf()来识别创建的对象类型
    组合继承模式的问题
  • 无论在什么情况下,都会调用两次超类型构造函数,一次是在子类型实例化的时候,第二次是在借用构造函数的时候,导致父类的原型对象会出现超类的实例属性或方法,解决此问题的办法先留个悬念....

原型式继承-------------------------------------------------------敷衍式代孕

关键词:基于已有对象创建新对象 对象关联 生下就撤

工具函数:
function object(o){ function F(){}; //创建临时类型 F.prototype = o; //让临时类型的原型对象指向传入的对象(继承) return new F(); //返回这个临时类型的实例(返回后就撤!) }
其实仔细观察这个函数,会发现临时类型F是起着代孕的作用,受人委托替传入的妈妈对象生了个宝宝,生完后孩子还没睁眼就悄然离开,所以宝宝只认当前的妈妈,有着妈妈的各种特征.
用法:
var mom = { name = Lily, hairColor: "black", skin:"white" } var baby = object(mom); baby.name = "Jack"; alert(baby.name) ; //"Jack" alert(baby.skin); //"white"
ES5规范通过Object.create()方法规范化原型式继承
该函数接收两个参数:
①用作新对象原型的对象
②为新对象定义额外属性的对象(可选),格式与Object.defineProperties相同,每个属性都是通过自己的描述符定义的.
该函数的缺点:只能定义额外属性,不能定义额外方法

原型式继承的优点

  • 抛弃了构造函数,而是把继承简化为对象之间的关联
  • 适用于想让一个对象与另一个对象保持类似的情况下使用

原型式继承的缺点

  • 通过原型式继承创建的对象是空对象,只不过是关联了另一个对象,但是在很多时候,我们需要对新对象进行加强,而这时候虽然可以在新对象增添特有的属性和方法,但是当我们需要很多个这样的对象的时候,一个个去增添,就显得很麻烦和难看,于是下面要将的寄生式继承可以帮到我们

寄生式继承----------------------------------------------------负责式代孕

关键词: 增强对象 生完培养一会再撤

function createBaby(mom){ var baby = object(mom); baby.sayHi = function(){ alert("hi!); } return baby; }
看完你大概懂了吧,寄生式继承类似原型式继承,只不过在内部对新对象进行增强,这样通过它产生的对象都是增强式的. 就好像一个负责的代孕妈妈,生完之后还要教会孩子一些技能,等到亲妈来了再离开,不过戏剧化的是,这个孩子还是只认亲妈(卧槽)
寄生式继承的优点

  • 解决了上面所提到的问题,可以快速新建一批增强式的对象.

寄生组合式继承-----------------------------最完美的继承方式(非最优雅)

关键词:只要超类构造函数的原型对象,不要它本身

相信你还记得上面留下的悬念吧,组合式继承会二次调用超类构造函数,寄生组合式继承就是为了解决这个问题的,其配合一个工具函数使用:
function inheritPrototype(subType,superType){ var prototype = object(superType.prototype); //创建一个新对象,关联超类构造函数的原型对象,不要构造函数 prototype.constructor = subType; //为新对象创建一个constructor指针并正确指向父类构造函数 subType.prototype = prototype; //重写父类构造函数的原型对象为新对象 } function SuperType(name){ this.name = name; this.colors = ["red","blue","green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name,age){ SuperType.call(this,name); this.age = age; } inheritPrototype(SubType,SuperType); SubType.prototype.sayAge = function(){ alert(this.age); };
虽然寄生组合式继承是引用类型最理想的继承范式,但是我还是觉得代码还是不够优雅,如果要数优雅程度的话,那就离不开ES6这块巨型语法糖了

上面介绍了的继承模式有:

  • 原型链

  • 借用构造函数

  • 组合继承

  • 原型式继承

  • 寄生式继承

  • 寄生组合式继承
    其中原型链和借用构造函数模式都有自己比较大的问题,组合继承把两者的优点融合在一起了,因此组合继承比较常见,但是组合继承也有自己的问题,而这个问题在寄生组合式继承中得到解决,寄生组合式继承代码不是那么的优雅,但是是最理想的方式.
    原型式继承和寄生式继承是一对儿,他们都抛弃了构造函数,而选择一种新的思维来进行继承------对象关联,这种方式代码最优雅.原型式新建立的对象是一个空对象,寄生式新建的对象则是一个增强的对象(用于大量生产).

      个人来说,原型式继承和寄生式继承是我比较顺眼的模式
      其他模式感觉都是为了使js这么语言向传统的类继承靠近的
      其实js的本质就是对象关联,而原型式继承和寄生式继承正体现了这一点
      这两种继承各有各的适合情景,原型式继承适合生产少量的对象后自己再进行增强
      寄生式继承适合生产大量的有类似功能的对象.
    

下面是我改写寄生式继承的一个工具函数
function createAndConnect(original,propertyObject){ var clone = Object.create(original); if(typeof propertyObject == "object"&&propertyObject!=null){ for(var key in propertyObject){ clone[key] = propertyObject[key]; } } return clone; }
多增添了一个用于加强对象的参数,就不用每次都得在内部加强了,而且使用方式显得相对优雅一点,如:
var chinese ={ country: "China", language:"Chinese", getLanguage: function(){ console.log("我的母语是"+this.language); }, skin: "yellow", aveHeight:1.71, face:["nose","eyes","mouse"] } var chineseStudent =createAndConnect(chinese,{ name:"LiAo", //独有属性 height:0.1, //独有属性 score: 59, //独有属性 secondLanguage:"English", //独有属性 skin:"a little yellow", //重写属性 getSecondLanguage:function(){ console.log("我的第二门语言是"+this.secondLanguage); } }) console.log(chineseStudent.name); // "LiAo" console.log(chineseStudent.skin); // "a little yellow" console.log(chineseStudent.face); //["nose","eyes","mouse"] chineseStudent.getLanguage(); //我的母语是Chinese chineseStudent.getSecondLanguage(); //我的第二门语言是English

最后的话

在createAndConnect函数(意思是创建和链接)的第二个参数中,你可以指定新对象自己的属性和方法,也可以"重写"原型对象的属性和方法,我认为这个才是js原型继承的精髓即对象关联.同时我也倡导大家用对象关联的思维去开发js应用!

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

推荐阅读更多精彩内容