国产激情自拍_国产9色视频_丁香花在线电影小说观看 _久久久久国产精品嫩草影院

首頁 > 編程 > JavaScript > 正文

再談javascript原型繼承

2019-11-20 13:56:19
字體:
供稿:網(wǎng)友

真正意義上來說Javascript并不是一門面向?qū)ο蟮恼Z言,沒有提供傳統(tǒng)的繼承方式,但是它提供了一種原型繼承的方式,利用自身提供的原型屬性來實(shí)現(xiàn)繼承。

原型與原型鏈

說原型繼承之前還是要先說說原型和原型鏈,畢竟這是實(shí)現(xiàn)原型繼承的基礎(chǔ)。
在Javascript中,每個(gè)函數(shù)都有一個(gè)原型屬性prototype指向自身的原型,而由這個(gè)函數(shù)創(chuàng)建的對象也有一個(gè)__proto__屬性指向這個(gè)原型,而函數(shù)的原型是一個(gè)對象,所以這個(gè)對象也會有一個(gè)__proto__指向自己的原型,這樣逐層深入直到Object對象的原型,這樣就形成了原型鏈。下面這張圖很好的解釋了Javascript中的原型和原型鏈的關(guān)系。

每個(gè)函數(shù)都是Function函數(shù)創(chuàng)建的對象,所以每個(gè)函數(shù)也有一個(gè)__proto__屬性指向Function函數(shù)的原型。這里需要指出的是,真正形成原型鏈的是每個(gè)對象的__proto__屬性,而不是函數(shù)的prototype屬性,這是很重要的。

原型繼承

基本模式

復(fù)制代碼 代碼如下:

var Parent = function(){
    this.name = 'parent' ;
} ;
Parent.prototype.getName = function(){
    return this.name ;
} ;
Parent.prototype.obj = {a : 1} ;

var Child = function(){
    this.name = 'child' ;
} ;
Child.prototype = new Parent() ;

var parent = new Parent() ;
var child = new Child() ;

console.log(parent.getName()) ; //parent
console.log(child.getName()) ; //child

這種是最簡單實(shí)現(xiàn)原型繼承的方法,直接把父類的對象賦值給子類構(gòu)造函數(shù)的原型,這樣子類的對象就可以訪問到父類以及父類構(gòu)造函數(shù)的prototype中的屬性。 這種方法的原型繼承圖如下:

這種方法的優(yōu)點(diǎn)很明顯,實(shí)現(xiàn)十分簡單,不需要任何特殊的操作;同時(shí)缺點(diǎn)也很明顯,如果子類需要做跟父類構(gòu)造函數(shù)中相同的初始化動(dòng)作,那么就得在子類構(gòu)造函數(shù)中再重復(fù)一遍父類中的操作:

復(fù)制代碼 代碼如下:

var Parent = function(name){
    this.name = name || 'parent' ;
} ;
Parent.prototype.getName = function(){
    return this.name ;
} ;
Parent.prototype.obj = {a : 1} ;

var Child = function(name){
    this.name = name || 'child' ;
} ;
Child.prototype = new Parent() ;

var parent = new Parent('myParent') ;
var child = new Child('myChild') ;

console.log(parent.getName()) ; //myParent
console.log(child.getName()) ; //myChild

上面這種情況還只是需要初始化name屬性,如果初始化工作不斷增加,這種方式是很不方便的。因此就有了下面一種改進(jìn)的方式。

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

復(fù)制代碼 代碼如下:

var Parent = function(name){
    this.name = name || 'parent' ;
} ;
Parent.prototype.getName = function(){
    return this.name ;
} ;
Parent.prototype.obj = {a : 1} ;

var Child = function(name){
    Parent.apply(this,arguments) ;
} ;
Child.prototype = new Parent() ;

var parent = new Parent('myParent') ;
var child = new Child('myChild') ;

console.log(parent.getName()) ; //myParent
console.log(child.getName()) ; //myChild

上面這種方法在子類構(gòu)造函數(shù)中通過apply調(diào)用父類的構(gòu)造函數(shù)來進(jìn)行相同的初始化工作,這樣不管父類中做了多少初始化工作,子類也可以執(zhí)行同樣的初始化工作。但是上面這種實(shí)現(xiàn)還存在一個(gè)問題,父類構(gòu)造函數(shù)被執(zhí)行了兩次,一次是在子類構(gòu)造函數(shù)中,一次在賦值子類原型時(shí),這是很多余的,所以我們還需要做一個(gè)改進(jìn):

復(fù)制代碼 代碼如下:

var Parent = function(name){
    this.name = name || 'parent' ;
} ;
Parent.prototype.getName = function(){
    return this.name ;
} ;
Parent.prototype.obj = {a : 1} ;

var Child = function(name){
    Parent.apply(this,arguments) ;
} ;
Child.prototype = Parent.prototype ;

var parent = new Parent('myParent') ;
var child = new Child('myChild') ;

console.log(parent.getName()) ; //myParent
console.log(child.getName()) ; //myChild

這樣我們就只需要在子類構(gòu)造函數(shù)中執(zhí)行一次父類的構(gòu)造函數(shù),同時(shí)又可以繼承父類原型中的屬性,這也比較符合原型的初衷,就是把需要復(fù)用的內(nèi)容放在原型中,我們也只是繼承了原型中可復(fù)用的內(nèi)容。上面這種方式的原型圖如下:

臨時(shí)構(gòu)造函數(shù)模式(圣杯模式)

上面借用構(gòu)造函數(shù)模式最后改進(jìn)的版本還是存在問題,它把父類的原型直接賦值給子類的原型,這就會造成一個(gè)問題,就是如果對子類的原型做了修改,那么這個(gè)修改同時(shí)也會影響到父類的原型,進(jìn)而影響父類對象,這個(gè)肯定不是大家所希望看到的。為了解決這個(gè)問題就有了臨時(shí)構(gòu)造函數(shù)模式。

復(fù)制代碼 代碼如下:

var Parent = function(name){
    this.name = name || 'parent' ;
} ;
Parent.prototype.getName = function(){
    return this.name ;
} ;
Parent.prototype.obj = {a : 1} ;

var Child = function(name){
    Parent.apply(this,arguments) ;
} ;
var F = new Function(){} ;
F.prototype = Parent.prototype ;
Child.prototype = new F() ;

var parent = new Parent('myParent') ;
var child = new Child('myChild') ;

console.log(parent.getName()) ; //myParent
console.log(child.getName()) ; //myChild

該方法的原型繼承圖如下:

很容易可以看出,通過在父類原型和子類原型之間加入一個(gè)臨時(shí)的構(gòu)造函數(shù)F,切斷了子類原型和父類原型之間的聯(lián)系,這樣當(dāng)子類原型做修改時(shí)就不會影響到父類原型。

我的方法

《Javascript模式》中到圣杯模式就結(jié)束了,可是不管上面哪一種方法都有一個(gè)不容易被發(fā)現(xiàn)的問題。大家可以看到我在'Parent'的prototype屬性中加入了一個(gè)obj對象字面量屬性,但是一直都沒有用。我們在圣杯模式的基礎(chǔ)上來看看下面這種情況:

復(fù)制代碼 代碼如下:

var Parent = function(name){
    this.name = name || 'parent' ;
} ;
Parent.prototype.getName = function(){
    return this.name ;
} ;
Parent.prototype.obj = {a : 1} ;

var Child = function(name){
    Parent.apply(this,arguments) ;
} ;
var F = new Function(){} ;
F.prototype = Parent.prototype ;
Child.prototype = new F() ;

var parent = new Parent('myParent') ;
var child = new Child('myChild') ;

console.log(child.obj.a) ; //1
console.log(parent.obj.a) ; //1
child.obj.a = 2 ;
console.log(child.obj.a) ; //2
console.log(parent.obj.a) ; //2

在上面這種情況中,當(dāng)我修改child對象obj.a的時(shí)候,同時(shí)父類的原型中的obj.a也會被修改,這就發(fā)生了和共享原型同樣的問題。出現(xiàn)這個(gè)情況是因?yàn)楫?dāng)訪問child.obj.a的時(shí)候,我們會沿著原型鏈一直找到父類的prototype中,然后找到了obj屬性,然后對obj.a進(jìn)行修改。再看看下面這種情況:

復(fù)制代碼 代碼如下:

var Parent = function(name){
    this.name = name || 'parent' ;
} ;
Parent.prototype.getName = function(){
    return this.name ;
} ;
Parent.prototype.obj = {a : 1} ;

var Child = function(name){
    Parent.apply(this,arguments) ;
} ;
var F = new Function(){} ;
F.prototype = Parent.prototype ;
Child.prototype = new F() ;

var parent = new Parent('myParent') ;
var child = new Child('myChild') ;

console.log(child.obj.a) ; //1
console.log(parent.obj.a) ; //1
child.obj.a = 2 ;
console.log(child.obj.a) ; //2
console.log(parent.obj.a) ; //2

這里有一個(gè)關(guān)鍵的問題,當(dāng)對象訪問原型中的屬性時(shí),原型中的屬性對于對象來說是只讀的,也就是說child對象可以讀取obj對象,但是無法修改原型中obj對象引用,所以當(dāng)child修改obj的時(shí)候并不會對原型中的obj產(chǎn)生影響,它只是在自身對象添加了一個(gè)obj屬性,覆蓋了父類原型中的obj屬性。而當(dāng)child對象修改obj.a時(shí),它先讀取了原型中obj的引用,這時(shí)候child.obj和Parent.prototype.obj是指向同一個(gè)對象的,所以child對obj.a的修改會影響到Parent.prototype.obj.a的值,進(jìn)而影響父類的對象。AngularJS中關(guān)于$scope嵌套的繼承方式就是模范Javasript中的原型繼承來實(shí)現(xiàn)的。
根據(jù)上面的描述,只要子類對象中訪問到的原型跟父類原型是同一個(gè)對象,那么就會出現(xiàn)上面這種情況,所以我們可以對父類原型進(jìn)行拷貝然后再賦值給子類原型,這樣當(dāng)子類修改原型中的屬性時(shí)就只是修改父類原型的一個(gè)拷貝,并不會影響到父類原型。具體實(shí)現(xiàn)如下:

復(fù)制代碼 代碼如下:

var deepClone = function(source,target){
    source = source || {} ;
    var toStr = Object.prototype.toString ,
        arrStr = '[object array]' ;
    for(var i in source){
        if(source.hasOwnProperty(i)){
            var item = source[i] ;
            if(typeof item === 'object'){
                target[i] = (toStr.apply(item).toLowerCase() === arrStr) : [] ? {} ;
                deepClone(item,target[i]) ;   
            }else{
                deepClone(item,target[i]) ;
            }
        }
    }
    return target ;
} ;
var Parent = function(name){
    this.name = name || 'parent' ;
} ;
Parent.prototype.getName = function(){
    return this.name ;
} ;
Parent.prototype.obj = {a : '1'} ;

var Child = function(name){
    Parent.apply(this,arguments) ;
} ;
Child.prototype = deepClone(Parent.prototype) ;

var child = new Child('child') ;
var parent = new Parent('parent') ;

console.log(child.obj.a) ; //1
console.log(parent.obj.a) ; //1
child.obj.a = '2' ;
console.log(child.obj.a) ; //2
console.log(parent.obj.a) ; //1


綜合上面所有的考慮,Javascript繼承的具體實(shí)現(xiàn)如下,這里只考慮了Child和Parent都是函數(shù)的情況下:

復(fù)制代碼 代碼如下:

var deepClone = function(source,target){
    source = source || {} ;
    var toStr = Object.prototype.toString ,
        arrStr = '[object array]' ;
    for(var i in source){
        if(source.hasOwnProperty(i)){
            var item = source[i] ;
            if(typeof item === 'object'){
                target[i] = (toStr.apply(item).toLowerCase() === arrStr) : [] ? {} ;
                deepClone(item,target[i]) ;   
            }else{
                deepClone(item,target[i]) ;
            }
        }
    }
    return target ;
} ;

var extend = function(Parent,Child){
    Child = Child || function(){} ;
    if(Parent === undefined)
        return Child ;
    //借用父類構(gòu)造函數(shù)
    Child = function(){
        Parent.apply(this,argument) ;
    } ;
    //通過深拷貝繼承父類原型   
    Child.prototype = deepClone(Parent.prototype) ;
    //重置constructor屬性
    Child.prototype.constructor = Child ;
} ;

總結(jié)

說了這么多,其實(shí)Javascript中實(shí)現(xiàn)繼承是十分靈活多樣的,并沒有一種最好的方法,需要根據(jù)不同的需求實(shí)現(xiàn)不同方式的繼承,最重要的是要理解Javascript中實(shí)現(xiàn)繼承的原理,也就是原型和原型鏈的問題,只要理解了這些,自己實(shí)現(xiàn)繼承就可以游刃有余。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
国产激情自拍_国产9色视频_丁香花在线电影小说观看 _久久久久国产精品嫩草影院
女人色在线免费视频| 国产传媒在线播放| 伊人永久在线| 精品女厕厕露p撒尿| 国产福利在线观看| 96久久久久久| 青青草视频在线免费观看| 日韩亚洲一区中文字幕| 久久香蕉一区| 午夜av在线播放| 国产福利片在线| www.香蕉视频在线观看| 九九热视频免费在线观看| 丁香花视频在线观看| 91中文字幕网| 中文字幕在线资源| 在线黄色国产电影| 国产精品一区二区婷婷| 夜夜操com| 国产视频福利| 激情亚洲综合网| 2019年中文字幕| 尤物网站在线| 免费女人毛片视频| 精品黄色免费中文电影在线播放| 99热播在线观看| 日p在线观看| 99reav在线| 91在线高清| 国产午夜在线| 国产农村av| 日本h视频在线观看| 国产福利在线观看| 国产精品天堂| 国产乱xxⅹxx国语对白| 欧美精品一区二区三区免费| 在线国产1区| 中文在线官网天堂| 国产91足控脚交在线观看| 丁香婷婷在线观看| 中文在线官网天堂| 国产福利视频在线观看| 国产精品18久久久久久久久久| www中文字幕在线观看| 亚洲欧美国产另类首页| 中文乱码字幕av网站| 2019天天操夜夜操| 在线免费观看污| 亚洲综合色视频在线观看| 一区二区三区四区在线免费视频| 国产福利视频在线观看| 国产精品视频一区麻豆| 国产视频福利| 69日小视频在线观看| 精品卡1卡2卡三卡免费网站| 国产丝袜精品丝袜| 91高清国产| 亚洲xxxxxx| 狠狠色丁香婷婷| 午夜在线小视频| 国产jizz| 久蕉依人在线视频| 国产黄色在线播放| 日本黄在线观看| 天堂在线中文资源| 国产精品区一区二| 99久久精品免费观看国产| 热99在线观看| 国产高清在线观看| 麻豆国产在线视频| 黄色一级片视频| 97一区二区三区| 中文字幕在线观看日本| av文字幕在线观看| 国产三级香港三韩国三级| 伊人电影在线观看| 国产精品一区二区三区视频网站 | 国产主播福利在线| 国产黄色在线免费观看| 久久久久久久久久久久网站| 最近中文av字幕在线中文| 精品视频麻豆入口| 最近中文字幕av免费高清 | 亚洲欧美精品日韩欧美| 中文字幕在线永久在线视频| 四虎网站在线观看| 国产福利av网站| 福利视频网站导航| 欧美卡一卡二| 日日夜夜中文字幕| av片在线观看| 精品视频三区| 国产超碰在线| 五月婷婷在线视频| 国产精品一区二区婷婷| 另类综合图区| www.三区| 欧美亚洲天堂| 开心婷婷激情| 九九99九九精彩| 九九热视频在线| 狠狠操视频网| 九九热在线观看视频| 欧美亚洲系列| 国产69久久| 中文字幕亚洲精品视频| 国产天堂在线| 91中文在线| 中文在线视频| 永久av在线| 免费在线黄色av| 久久精品国产亚洲a∨麻豆| 日本欧洲一区| 狠狠操视频网| 国产天堂资源| 伊人永久在线| 九九99九九精彩| 国产视频中文字幕在线观看| 国产9色视频| www.毛片| 国产秒拍福利视频露脸| 国产日产精品久久久久久婷婷| 国产激情视频一区二区| 国产欧美日韩精品综合| 国产粉嫩一区二区三区在线观看| 国产aⅴ超薄肉色丝袜交足| 永久免费av网站| 国产在线你懂得| 国产高清自拍视频在线观看 | 亚洲欧洲成人| 国产专区在线播放| 69国产精品| 国产男女猛烈无遮挡免费视频| 国产区视频在线观看| 亚洲人av在线| 国产精品免费视频一区一| 国产成人天天5g影院| 免费中文字幕| 精精国产xxxx视频在线中文版 | www黄在线观看| 国产色在线播放| 免费av不卡在线观看| 97视频网站| 国产特级嫩嫩嫩bbb| 黄色毛片在线观看| 亚洲视频精品在线观看| 国产美女福利在线| 日本电影全部在线观看网站视频 | 中文国产字幕在线观看| 成人精品一区二区三区免费| av片在线观看| 99re在线视频播放| 国产国产国产国产国产国产| 午夜视频免费在线观看| 久色视频在线观看| 日本免费视频www| 中文在线观看视频| 国产成在线观看免费视频| 丁香视频五月| gogogogo高清视频在线| 国产9色视频| 精品卡一卡卡2卡3网站| 在线中文免费视频| 中文在线视频观看| 在线播放国产区| 亚洲伊人网在线观看| 天天操夜夜添| 老师我好爽再深一点的视频| 日本电影全部在线观看网站视频| av在线1区2区| jizz一区二区三区| 国产在线拍揄自揄拍视频| 丁香花高清在线观看完整版 | 大香伊人中文字幕精品| www.大网伊人| 久久久久国产精品嫩草影院| 黄色国产网站在线观看| 国产丝袜在线观看视频| 中文字幕av高清| 欧美视频免费一区二区三区| 国产另类图片| 2018中文字幕在线| sese在线视频| 国产三级在线免费| 亚洲an天堂an在线观看| 老司机精品视频一区二区| 久久香蕉一区| 精品剧情v国产在线观看| 蜜桃视频网站在线| 国产馆av播放| 久久国产情侣| 91视频久色| 国产九色视频| 青青久草在线| 国产成人亚洲精品播放器下载| 爱福利在线视频| 97视频在线| 最近中文字幕av免费高清| v天堂福利视频在线观看| 国产精品免费视频一区一|