JavaScript設(shè)計(jì)模式學(xué)習(xí)之繼承

本文僅僅是記錄自己學(xué)習(xí)的心得體會(huì),如果有誤,歡迎指出,非原創(chuàng),具體請(qǐng)參考:《JavaScript設(shè)計(jì)模式》 張容銘 著

1.子類的原型對(duì)象繼承——類式繼承
//聲明父類
function ParentClass() {
  this.ParentValue = true;
}
ParentClass.prototype.getParentValue = function () {
  return this.ParentValue;
}
//聲明子類
function ChildClass() {
  this.ChildValue = false;
}
ChildClass.prototype = new ParentClass();//繼承父類
ChildClass.prototype.getChildValue = function () {
  return this.ChildValue;
}

這里實(shí)現(xiàn)繼承是將父類的實(shí)例賦予給了子類的原型

var newChild = new ChildClass();
console.log(newChild)
console.log(newChild.__proto__)

輸出結(jié)果:


輸出結(jié)果.png

這里的newChild是子類的實(shí)例,newChild的原型對(duì)象現(xiàn)在是父類的實(shí)例,這個(gè)時(shí)候newChild繼承了父類的屬性以及原型上的方法

使用:

var result = newChild .getChildValue();
var result1 = newChild .getParentValue();
console.log(result);//false
console.log(result1);//true
子類繼承的缺點(diǎn):

1.如果父類的屬性中含有引用類型,那么在子類中改變后,父類的屬性的值也會(huì)改變。
2.因?yàn)檫@種繼承是將父類的實(shí)例化對(duì)象賦給子類的原型,所以這里沒(méi)有辦法向父類傳遞參數(shù)


//聲明父類
function ParentClass() {
//引用類型屬性
  this.booksName = ['JavaScript','CSS3','HTML5'];
}
ParentClass.prototype.getParentValue = function () {
  return this.booksName;
}
//聲明子類
function ChildClass() {
  this.ChildValue = false;
}
ChildClass.prototype = new ParentClass();
ChildClass.prototype.getChildValue = function () {
  return this.ChildValue;
}
var newChild1 = new ChildClass();
var newChild2  = new ChildClass();
console.log(newChild2.booksName)//["JavaScript","CSS3","HTML5"]
newChild1.booksName.push('JQuery'); //別人修改這個(gè)值后
console.log(newChild2.booksName)//["JavaScript","CSS3","HTML5","JQuery"]
2.構(gòu)造式繼承
//聲明父類
function ParentClass(bookId) {
  //引用類型屬性
  this.booksName = ['JS','CSS3','HTML5']
  this.id = bookId
}
//父類添加原型方法
ParentClass.prototype.getBooks = function () {
  console.log(this.booksName)
}
//子類
function ChildClass(bookId) {
  //繼承父類
  ParentClass.call(this,(bookId))
}
//創(chuàng)建兩個(gè)子類實(shí)例對(duì)象
var newChild1 = new ChildClass(101);
var newChild2 = new ChildClass(102);
newChild1.booksName.push('JQ');
console.log(newChild1.booksName);//["JS","CSS3","HTML5","JQ"]
console.log(newChild1.id);//101
console.log(newChild2.booksName);//["JS","CSS3","HTML5"]
console.log(newChild2.id);//102
newChild1.getBooks();//Uncaught TypeError: newChild1.getBooks is not a function

call這個(gè)方法可以更改函數(shù)的作用環(huán)境,在子類中,對(duì)ParentClass調(diào)用這個(gè)方法,就是將子類的變量在父類中執(zhí)行了一遍。父類中是給this綁定屬性的,new對(duì)象的時(shí)候這個(gè)this指向new的對(duì)象(這里是newChild1 和newChild2),這樣就把父類的屬性都復(fù)制了到了這兩個(gè)實(shí)例化的對(duì)象上,所以當(dāng)我改變newChild1.booksName的時(shí)候沒(méi)有改變到newChild2.booksName的值

這種辦法既可以傳參,也可以防止父類中的引用類型屬性被修改,是不是剛好和類式繼承互補(bǔ)呢,SO?

3.組合式繼承
//聲明父類
function ParentClass(name) {
  this.name = name
  this.booksName = ['JS','HTML5','CSS3']
}
//父類原型公共方法
ParentClass.prototype.getBookName = function () {
  console.log(this.name)
}
//聲明子類
function ChildClass(name,time) {
  this.time = time
  ParentClass.call(this,(name))
}
//類式繼承
ChildClass.prototype = new ParentClass()
//子類原型方法
ChildClass.prototype.getBookTime = function () {
  console.log(this.time)
}

var book1 = new ChildClass('JQ',2011);
var book2 = new ChildClass('Vue',2015);

book1.getBookTime();  //2011
book1.getBookName();  //JQ
book1.booksName.push('React');
book2.getBookTime();  //2015
book2.getBookName();  //Vue
console.log(book1.booksName);  //["JS", "HTML5", "CSS3", "React"]
console.log(book2.booksName);  //["JS", "HTML5", "CSS3"]

4.原型式繼承

function innerObject(fn) {
  function Fun() {
    //new 一個(gè)過(guò)渡函數(shù)
  }
  Fun.prototype = fn; //過(guò)渡函數(shù)的原型指向傳入的對(duì)象
  return new Fun(); //返回原型繼承了fn的實(shí)例
}

這種方法有缺點(diǎn):
1.和類似繼承很像,如果傳入的對(duì)象屬性中有引用類型,那么將產(chǎn)生和類似繼承一樣的問(wèn)題,公用了一個(gè)屬性,也會(huì)容易被其他的修改而發(fā)生改變
2.但是在此基礎(chǔ)上推進(jìn)可以得到寄生式繼承

5.寄生式繼承

function innerObject(fn) {
 function Fun() {

 }
 Fun.prototype = fn;
 return new Fun();
}

var book = {
 bookName : 'js book',
 alikeBooks : ['css book','html book']
};
function CreatBook() {
 var newBook = innerObject(book);
 newBook.getName = function () {
   console.log(bookName)
 }
 return newBook;
}
var book1 = new CreatBook();
var book2 = new CreatBook();
book1.alikeBooks.push('JQ');
console.log(book1)
console.log(book2)
console.log(book1.alikeBooks)//['css book','html book','JQ']
console.log(book2.alikeBooks)//['css book','html book','JQ']

book1 && book2輸出結(jié)果:

book1 && book2輸出結(jié)果.png

書(shū)上說(shuō)“其實(shí)寄生式繼承就是對(duì)原型繼承的第二次封裝,并且在這第二次封裝的過(guò)程中對(duì)繼承的對(duì)象進(jìn)行了擴(kuò)展,這樣新創(chuàng)建的對(duì)象不僅有父類的屬性和方法,還添加新的屬性和方法”

6.寄生組合式繼承

function innerObject(fn) {
  function Fun() {}
  Fun.prototype = fn;
  return new Fun();
}
function innerPrototypeObject(childClass, parentClass) {
  //傳入父類的原型 得到繼承了父類原型的對(duì)象newChildClassPrototype 
  var newChildClassPrototype = new innerObject(parentClass.prototype);
  //將繼承了父類原型的對(duì)象newChildClassPrototype 的構(gòu)造函數(shù)指向子類
  newChildClassPrototype.constructor = childClass;
  //重寫(xiě)子類的原型,newChildClassPrototype成為子類的原型
  childClass.prototype = newChildClassPrototype;
}

測(cè)試:

function innerObject(fn) {
  function Fun() {}
  Fun.prototype = fn;
  return new Fun();
}
function innerPrototypeObject(childClass, parentClass) {
  //傳入父類的原型 得到繼承了父類原型的對(duì)象newChildClassPrototype 
  var newChildClassPrototype = new innerObject(parentClass.prototype);
  //將繼承了父類原型的對(duì)象newChildClassPrototype 的構(gòu)造函數(shù)指向子類
  newChildClassPrototype.constructor = childClass;
  //重寫(xiě)子類的原型,newChildClassPrototype成為子類的原型
  childClass.prototype = newChildClassPrototype;
}

function parentClass(bookname) {
  this.name = bookname
  this.color = ['red','blue','green']
}
parentClass.prototype.getName = function () {
  console.log(this.name)
}
function childChass(bname,time) {
  parentClass.call(this,(bname))//繼承父類屬性
  this.time = time
}
innerPrototypeObject(childChass,parentClass);//繼承父類原型
childChass.prototype.getTime = function () {
  console.log(this.time)
}
var newbook1 = new childChass('js',2015);
var newbook2 = new childChass('jq',2017);
console.log(newbook1)
console.log(newbook2)
newbook1.color.push('yellow');
console.log(newbook1.color);  //['red','blue','green','yellow']
console.log(newbook2.color);  //['red','blue','green']
newbook1.getTime();  //2015
newbook2.getName();  //jq

這里修改了實(shí)例newbook1的color這個(gè)屬性,但是并沒(méi)有影響到newbook2實(shí)例的屬性的值,newbook1&&newbook2輸出結(jié)果:

newbook1&&newbook2輸出結(jié)果.png

現(xiàn)在處于昏迷狀態(tài),讓我捋捋再改。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 我們?cè)趯?duì)象創(chuàng)建模式中討論過(guò),對(duì)象創(chuàng)建的模式就是定義對(duì)象模板的方式。有了模板以后,我們就可以輕松地創(chuàng)建多個(gè)結(jié)構(gòu)相同的...
    csRyan閱讀 1,019評(píng)論 0 7
  • 博客內(nèi)容:什么是面向?qū)ο鬄槭裁匆嫦驅(qū)ο竺嫦驅(qū)ο缶幊痰奶匦院驮瓌t理解對(duì)象屬性創(chuàng)建對(duì)象繼承 什么是面向?qū)ο?面向?qū)ο?..
    _Dot912閱讀 1,534評(píng)論 3 12
  • 設(shè)計(jì)模式匯總 一、基礎(chǔ)知識(shí) 1. 設(shè)計(jì)模式概述 定義:設(shè)計(jì)模式(Design Pattern)是一套被反復(fù)使用、多...
    MinoyJet閱讀 4,081評(píng)論 1 15
  • 繼承 Javascript中繼承都基于兩種方式:1.通過(guò)原型鏈繼承,通過(guò)修改子類原型的指向,使得子類實(shí)例通過(guò)原型鏈...
    LeoCong閱讀 404評(píng)論 0 0
  • 它無(wú)聲無(wú)息地折磨著你,它是你長(zhǎng)期失落和悔恨的根源,它讓你感覺(jué)自己是生活的旁觀者。它讓你感到沮喪的不是“沒(méi)有實(shí)現(xiàn)夢(mèng)想...
    曉橙故事閱讀 465評(píng)論 0 1

友情鏈接更多精彩內(nèi)容