最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript繼承基礎(chǔ)講解(原型鏈、借用構(gòu)造函數(shù)、混合模式、原型式繼承、寄生式繼承、寄生組合式繼承)

 更新時(shí)間:2014年08月16日 23:08:55   作者:wuyuchang  
這篇文章主要介紹了JavaScript繼承基礎(chǔ)講解,原型鏈、借用構(gòu)造函數(shù)、混合模式、原型式繼承、寄生式繼承、寄生組合式繼承,需要的朋友可以參考下

說(shuō)好的講解JavaScript繼承,可是遲遲到現(xiàn)在講解。廢話不多說(shuō),直接進(jìn)入正題。

  既然你想了解繼承,證明你對(duì)JavaScript面向?qū)ο笠呀?jīng)有一定的了解,如還有什么不理解的可以參考《面向?qū)ο驤S基礎(chǔ)講解,工廠模式、構(gòu)造函數(shù)模式、原型模式、混合模式、動(dòng)態(tài)原型模式》,接下來(lái)講一般通過(guò)那些方法完成JavaScript的繼承。

  原型鏈

  JavaScript中實(shí)現(xiàn)繼承最簡(jiǎn)單的方式就是使用原型鏈,將子類(lèi)型的原型指向父類(lèi)型的實(shí)例即可,即“子類(lèi)型.prototype = new 父類(lèi)型();”,實(shí)現(xiàn)方法如下:

// 為父類(lèi)型創(chuàng)建構(gòu)造函數(shù)
function SuperType() {
  this.name = ['wuyuchang', 'Jack', 'Tim'];
  this.property = true;
}

// 為父類(lèi)型添加方法
SuperType.prototype.getSuerperValue = function() {
  return this.property;
}

// 為子類(lèi)型創(chuàng)建構(gòu)造函數(shù)
function SubType() {
  this.test = ['h1', 'h2', 'h3', 'h4'];
  this.subproperty = false;
}

// 實(shí)現(xiàn)繼承的關(guān)鍵步驟,子類(lèi)型的原型指向父類(lèi)型的實(shí)例
SubType.prototype = new SuperType();

// 在此處給子類(lèi)型添加方法,一定要在實(shí)現(xiàn)繼承之后,否則會(huì)在將指針指向父類(lèi)型的實(shí)例,則方法為空
SubType.prototype.getSubValue = function() {
  return this.subproperty;
}


/* 以下為測(cè)試代碼示例 */
var instance1 = new SubType();
instance1.name.push('wyc');
instance1.test.push('h5');
alert(instance1.getSuerperValue());    // true
alert(instance1.getSubValue());      // false
alert(instance1.name);          // wuyuchang,Jack,Tim,wyc
alert(instance1.test);          // h1,h2,h3,h4,h5


var instance2 = new SubType();
alert(instance2.name);          // wuyuchang,Jack,Tim,wyc
alert(instance2.test);          // h1,h2,h3,h4

可以看到如上的代碼就是通過(guò)原型鏈實(shí)現(xiàn)的一個(gè)簡(jiǎn)單的繼承,但看到測(cè)試代碼示例中還是存在些問(wèn)題。相信看了我的博文《面向?qū)ο驤S基礎(chǔ)講解,工廠模式、構(gòu)造函數(shù)模式、原型模式、混合模式、動(dòng)態(tài)原型模式》的童鞋一定知道原型鏈代碼存在的第一個(gè)問(wèn)題是由于子類(lèi)型的原型是父類(lèi)型的實(shí)例,也就是子類(lèi)型的原型中包含的父類(lèi)型的屬性,從而導(dǎo)致引用類(lèi)型值的原型屬性會(huì)被所有實(shí)例所共享。以上代碼的instance1.name.push('wyc');就可以證明此問(wèn)題的存在。而原型鏈的第二個(gè)問(wèn)題就是:在創(chuàng)建子類(lèi)型的實(shí)例時(shí),不能向超類(lèi)型的構(gòu)造函數(shù)中傳遞參數(shù)。因此我們?cè)趯?shí)際開(kāi)發(fā)中,很少單獨(dú)使用原型鏈。 

   借用構(gòu)造函數(shù)

  為了解決原型鏈中存在的兩個(gè)問(wèn)題,開(kāi)發(fā)人員開(kāi)始使用一種叫做借用構(gòu)造函數(shù)的技術(shù)來(lái)解決原型鏈中存在的問(wèn)題。這種技術(shù)的實(shí)現(xiàn)思路也挺簡(jiǎn)單,只需要在子類(lèi)型的構(gòu)造函數(shù)內(nèi)調(diào)用父類(lèi)型的構(gòu)造函數(shù)即可。別忘了,函數(shù)只不過(guò)是在特定環(huán)境中執(zhí)行代碼的對(duì)象,因此可以通過(guò)apply()或call()方法執(zhí)行構(gòu)造函數(shù)。代碼如下:

// 為父類(lèi)型創(chuàng)建構(gòu)造函數(shù)
function SuperType(name) {
  this.name = name;
  this.color = ['pink', 'yellow'];
  this.property = true;

  this.testFun = function() {
    alert('http://tools.jb51.net/');
  }
}

// 為父類(lèi)型添加方法
SuperType.prototype.getSuerperValue = function() {
  return this.property;
}

// 為子類(lèi)型創(chuàng)建構(gòu)造函數(shù)
function SubType(name) {
  SuperType.call(this, name);
  this.test = ['h1', 'h2', 'h3', 'h4'];
  this.subproperty = false;
}

// 在此處給子類(lèi)型添加方法,一定要在實(shí)現(xiàn)繼承之后,否則會(huì)在將指針指向父類(lèi)型的實(shí)例,則方法為空
SubType.prototype.getSubValue = function() {
  return this.subproperty;
}


/* 以下為測(cè)試代碼示例 */
var instance1 = new SubType(['wuyuchang', 'Jack', 'Nick']);
instance1.name.push('hello');
instance1.test.push('h5');
instance1.color.push('blue');
instance1.testFun();            // http://tools.jb51.net/
alert(instance1.name);            // wuyuchang,Jack,Nick,hello
// alert(instance1.getSuerperValue());    // error 報(bào)錯(cuò)
alert(instance1.test);            // h1,h2,h3,h4,h5    
alert(instance1.getSubValue());        // false    
alert(instance1.color);            // pink,yellow,blue

var instance2 = new SubType('wyc');
instance2.testFun();            // http://tools.jb51.net/
alert(instance2.name);            // wyc    
// alert(instance2.getSuerperValue());    // error 報(bào)錯(cuò)
alert(instance2.test);            // h1,h2,h3,h4
alert(instance2.getSubValue());        // false
alert(instance2.color);            // pink,yellow

可以看到以上代碼中子類(lèi)型SubType的構(gòu)造函數(shù)內(nèi)通過(guò)調(diào)用父類(lèi)型"SuperType.call(this, name);",從而實(shí)現(xiàn)了屬性的繼承,也可以在子類(lèi)型創(chuàng)建實(shí)例的時(shí)候?yàn)楦割?lèi)型傳遞參數(shù)了,但新的問(wèn)題又來(lái)了??梢钥吹轿以诟割?lèi)型的構(gòu)造函數(shù)中定義了一個(gè)方法:testFun,在父類(lèi)型的原型中定義了一個(gè)方法:getSuperValue??墒窃?span style="color: #ff0000">實(shí)例化子類(lèi)型后仍然是無(wú)法調(diào)用父類(lèi)型的原型中定義的方法getSuperValue,只能調(diào)用父類(lèi)型中構(gòu)造函數(shù)的方法:testFun。這就同創(chuàng)建對(duì)象中只使用構(gòu)造函數(shù)模式一樣,使得函數(shù)沒(méi)有復(fù)用性可言??紤]到這些問(wèn)題,借用構(gòu)造函數(shù)的技術(shù)也是很少單獨(dú)使用的。

組合繼承(原型鏈+借用構(gòu)造函數(shù))

  顧名思義,組合繼承就是結(jié)合使用原型鏈與借用構(gòu)造函數(shù)的優(yōu)點(diǎn),組合而成的一個(gè)模式。實(shí)現(xiàn)也很簡(jiǎn)單,既然是結(jié)合,那當(dāng)然結(jié)合了兩方的優(yōu)點(diǎn),即原型鏈繼承方法,而在構(gòu)造函數(shù)繼承屬性。具體代碼實(shí)現(xiàn)如下:

// 為父類(lèi)型創(chuàng)建構(gòu)造函數(shù)
function SuperType(name) {
  this.name = name;
  this.color = ['pink', 'yellow'];
  this.property = true;

  this.testFun = function() {
    alert('http://tools.jb51.net/');
  }
}

// 為父類(lèi)型添加方法
SuperType.prototype.getSuerperValue = function() {
  return this.property;
}

// 為子類(lèi)型創(chuàng)建構(gòu)造函數(shù)
function SubType(name) {
  SuperType.call(this, name);
  this.test = ['h1', 'h2', 'h3', 'h4'];
  this.subproperty = false;
}

SubType.prototype = new SuperType();

// 在此處給子類(lèi)型添加方法,一定要在實(shí)現(xiàn)繼承之后,否則會(huì)在將指針指向父類(lèi)型的實(shí)例,則方法為空
SubType.prototype.getSubValue = function() {
  return this.subproperty;
}


/* 以下為測(cè)試代碼示例 */
var instance1 = new SubType(['wuyuchang', 'Jack', 'Nick']);
instance1.name.push('hello');
instance1.test.push('h5');
instance1.color.push('blue');
instance1.testFun();            // http://tools.jb51.net/
alert(instance1.name);            // wuyuchang,Jack,Nick,hello
alert(instance1.getSuerperValue());      // true
alert(instance1.test);            // h1,h2,h3,h4,h5    
alert(instance1.getSubValue());        // false    
alert(instance1.color);            // pink,yellow,blue

var instance2 = new SubType('wyc');
instance2.testFun();            // http://tools.jb51.net/
alert(instance2.name);            // wyc    
alert(instance2.getSuerperValue());      // true
alert(instance2.test);            // h1,h2,h3,h4
alert(instance2.getSubValue());        // false
alert(instance2.color);            // pink,yellow

以上代碼通過(guò)SuperType.call(this, name);繼承父類(lèi)型的屬性,通過(guò)SubType.prototype = new SuperType();繼承父類(lèi)型的方法。以上代碼很方便的解決了原型鏈與借用構(gòu)造函數(shù)所遇到的問(wèn)題,成為了JavaScript中最為常用的實(shí)例繼承的方法。但混合模式也并非沒(méi)有缺點(diǎn),可以看到在以上代碼中在繼承方法的時(shí)候?qū)嶋H已經(jīng)繼承了父類(lèi)型的屬性,只不過(guò)此時(shí)對(duì)于引用類(lèi)型屬于共享的,因此在子類(lèi)型的構(gòu)造函數(shù)內(nèi)在次調(diào)用父類(lèi)型的構(gòu)造函數(shù)從而繼承了父類(lèi)型的屬性而去覆蓋了原型中所繼承的屬性,這樣調(diào)用兩次構(gòu)造函數(shù)顯然沒(méi)有必要,但有什么方法可以解決呢?在解決此問(wèn)題時(shí)先看以下兩個(gè)模式。

原型式繼承

  原型式繼承的的實(shí)現(xiàn)方法與普通繼承的實(shí)現(xiàn)方法不同,原型式繼承并沒(méi)有使用嚴(yán)格意義上的構(gòu)造函數(shù),而是借助原型可以基于已有的對(duì)象創(chuàng)建新對(duì)象,同時(shí)還不必因此創(chuàng)建自定義類(lèi)型。具體代碼如下:

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

代碼示例:

/* 原型式繼承 */
function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}

var person = {
  name : 'wuyuchang',
  friends : ['wyc', 'Nicholas', 'Tim']
}

var anotherPerson = object(person);
anotherPerson.name = 'Greg';
anotherPerson.friends.push('Bob');

var anotherPerson2 = object(person);
anotherPerson2.name = 'Jack';
anotherPerson2.friends.push('Rose');

alert(person.friends);  // wyc,Nicholas,Tim,Bob,Rose

寄生式繼承

/* 寄生式繼承 */
function createAnother(original) {
  var clone = object(original);
  clone.sayHi = function() {
    alert('hi');
  }
  return clone;
}

使用示例:

/* 原型式繼承 */
function object(o) {
  function F() {}
  F.prototype = o;
  return new F();
}
   
/* 寄生式繼承 */
function createAnother(original) {
  var clone = object(original);
  clone.sayHi = function() {
    alert('hi');
  }
  return clone;
}

var person = {
  name : 'wuyuchang',
  friends : ['wyc', 'Nicholas', 'Rose']
}
var anotherPerson = createAnother(person);
anotherPerson.sayHi();

寄生組合式繼承

  前面說(shuō)過(guò)了JavaScrip中組合模式實(shí)現(xiàn)繼承的缺點(diǎn),現(xiàn)在我們就來(lái)解決它的缺點(diǎn),實(shí)現(xiàn)思路是,對(duì)于構(gòu)造函數(shù)繼承屬性,而原型鏈的混成形式繼承方法,即不用在繼承方法的時(shí)候?qū)嵗割?lèi)型的構(gòu)造函數(shù)。代碼如下:

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;
}

而在使用時(shí)只需要將組合模式中的“SubType.prototype = new SuperType();”這行代碼替換成inheritPrototype(subType, superType);即可。寄生組合式繼承的高效率體現(xiàn)在它只調(diào)用了一次父類(lèi)型構(gòu)造函數(shù),避免了創(chuàng)建不必要的或多余的屬性。與此同時(shí),原型鏈還能保持不變,因此,還能夠正常使用instanceof和isPrototypeof()。這也是目前來(lái)說(shuō)最理想的繼承方式了,目前也在向這種模式轉(zhuǎn)型。(YUI也使用了這種模式。)

此博文參考《JavaScript高級(jí)程序設(shè)計(jì)第3版》,代碼為經(jīng)過(guò)改寫(xiě),更具體,并加了注釋使大家更易懂。如對(duì)JS繼承方面有獨(dú)到見(jiàn)解的童鞋不別吝嗇,回復(fù)您的見(jiàn)解供大家參考!

相關(guān)文章

  • 微信小程序云開(kāi)發(fā)實(shí)現(xiàn)增刪改查功能

    微信小程序云開(kāi)發(fā)實(shí)現(xiàn)增刪改查功能

    這篇文章主要為大家詳細(xì)介紹了微信小程序云開(kāi)發(fā)實(shí)現(xiàn)增刪改查功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • 前端代碼按需加載(懶加載)的實(shí)現(xiàn)方案

    前端代碼按需加載(懶加載)的實(shí)現(xiàn)方案

    懶加載也叫做延遲加載、按需加載,指的是在長(zhǎng)網(wǎng)頁(yè)中延遲加載圖片數(shù)據(jù),是一種較好的網(wǎng)頁(yè)性能優(yōu)化的方式,那么如何實(shí)現(xiàn)前端代碼的按需加載(懶加載)呢,本文給大家介紹了三種實(shí)現(xiàn)方式,需要的朋友可以參考下
    2025-06-06
  • js+html+css實(shí)現(xiàn)簡(jiǎn)單電子時(shí)鐘

    js+html+css實(shí)現(xiàn)簡(jiǎn)單電子時(shí)鐘

    這篇文章主要為大家詳細(xì)介紹了js+html+css實(shí)現(xiàn)簡(jiǎn)單電子時(shí)鐘,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • JS 俄羅斯方塊完美注釋版代碼

    JS 俄羅斯方塊完美注釋版代碼

    JS俄羅斯方塊完美注釋版 v 1.01 從學(xué)c語(yǔ)言那一會(huì)兒都想寫(xiě)一個(gè)俄羅斯方塊,可是每次動(dòng)起手總覺(jué)得難度太大. 今天終于用了大約4個(gè)小時(shí)寫(xiě)出來(lái)了. 其中在涉及到方塊變型的時(shí)候還咨詢了
    2008-11-11
  • JavaScript制作頁(yè)面倒計(jì)時(shí)器的實(shí)現(xiàn)

    JavaScript制作頁(yè)面倒計(jì)時(shí)器的實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了JavaScript制作頁(yè)面倒計(jì)時(shí)器的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-03-03
  • javascript每日必學(xué)之條件分支

    javascript每日必學(xué)之條件分支

    javascript每日必學(xué)之條件分支,本文的主要內(nèi)容就是介紹的邏輯條件分支,循環(huán),感興趣的小伙伴們可以參考一下
    2016-02-02
  • JavaScript中常用的六種互動(dòng)方法示例

    JavaScript中常用的六種互動(dòng)方法示例

    這篇文章主要介紹了JavaScript中常用的六種互動(dòng)方法示例,是個(gè)人的一些經(jīng)驗(yàn)總結(jié),這里分享給大家,希望對(duì)大家能夠有所幫助。
    2015-03-03
  • 基于JavaScript實(shí)現(xiàn)一個(gè)簡(jiǎn)單的事件觸發(fā)器

    基于JavaScript實(shí)現(xiàn)一個(gè)簡(jiǎn)單的事件觸發(fā)器

    這篇文章主要為大家詳細(xì)介紹了如何使用JavaScript實(shí)現(xiàn)一個(gè)簡(jiǎn)單的事件觸發(fā)器,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-01-01
  • 你可能不知道的JavaScript的new Function()方法

    你可能不知道的JavaScript的new Function()方法

    JavaScript的精神領(lǐng)袖Douglas Crockford曾說(shuō)過(guò)JavaScript是程序員唯一不需要學(xué)習(xí)就能直接使用的語(yǔ)言. 在編程中確實(shí)是如此
    2014-04-04
  • JavaScript庫(kù)urlcat?之URL構(gòu)建器庫(kù)

    JavaScript庫(kù)urlcat?之URL構(gòu)建器庫(kù)

    這篇文章主要介紹了JavaScript庫(kù)urlcat之URL構(gòu)建器庫(kù),urlcat?是一個(gè)小型的JavaScript庫(kù),使構(gòu)建URL非常方便并防止常見(jiàn)錯(cuò)誤。下文來(lái)看對(duì)其詳細(xì)介紹吧,需要的小伙伴可以參考一下
    2022-02-02

最新評(píng)論

宣化县| 甘南县| 松桃| 哈巴河县| 成都市| 宜君县| 鞍山市| 敖汉旗| 拜城县| 昭通市| 柳江县| 莱阳市| 邢台县| 宝应县| 洪雅县| 嘉荫县| 玛纳斯县| 迁西县| 华宁县| 集安市| 扎囊县| 邵武市| 高碑店市| 丹寨县| 碌曲县| 贵港市| 陇南市| 威海市| 绥江县| 镇沅| 收藏| 沙湾县| 平顺县| 嫩江县| 枝江市| 永福县| 江西省| 隆化县| 大同县| 临漳县| 岳普湖县|