精品伊人久久大香线蕉,开心久久婷婷综合中文字幕,杏田冲梨,人妻无码aⅴ不卡中文字幕

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Javascript繼承機(jī)制總結(jié) + 散分
                              Javascript繼承 
一直想對Javascript再次做一些總結(jié),正好最近自己寫了一個(gè)小型Js UI庫,總結(jié)了一下Js的繼承機(jī)制,在網(wǎng)上也看了一些前輩們博客里的總結(jié),感覺分析不是特別全面。這里僅僅是把自己的學(xué)習(xí)體會拿出來分享一下,希望對大家學(xué)習(xí)Javascript有所幫助。 

Javascript本身是從Perl語言的語法演變而來的,本質(zhì)上是腳本語言,隨著版本的更新逐漸加入的對面向?qū)ο蟮哪M。我認(rèn)為Js的面向?qū)ο竽M總體上做得還是不錯(cuò)的,因?yàn)槲覀儾荒苊娜魏我环N理念,不能純粹的為了OOP而OOP,我們需要抓住的是面向?qū)ο蟮暮锰幍降资鞘裁矗繛榱诉@些優(yōu)點(diǎn)去OOP,才是最明智的選擇,所以說Js做得還不錯(cuò)。 

Js的繼承在很多書里面細(xì)致的分了很多種類型和實(shí)現(xiàn)方式,大體上就是兩種:對象冒充、原型方式。這兩種方式各有優(yōu)點(diǎn)和缺陷,這里我先列舉出來,再從底層分析區(qū)別: 

(一)對象冒充 
JavaScript code?
1
2
3
4
5
6
7
8
9
10
11
12
function A(name){
    this.name = name;
    this.sayHello = function(){alert(this.name+” say Hello!”);};
}
function B(name,id){
    this.temp = A;
    this.temp(name);        //相當(dāng)于new A();
    delete this.temp;        //防止在以后通過temp引用覆蓋超類A的屬性和方法
     this.id = id;    
    this.checkId = function(ID){alert(this.id==ID)};
}


當(dāng)構(gòu)造對象B的時(shí)候,調(diào)用temp相當(dāng)于啟動A的構(gòu)造函數(shù),注意這里的上下文環(huán)境中的this對象是B的實(shí)例,所以在執(zhí)行A構(gòu)造函數(shù)腳本時(shí),所有A的變量和方法都會賦值給this所指的對象,即B的實(shí)例,這樣子就達(dá)到B繼承了A的屬性方法的目的。之后刪除臨時(shí)引用temp,是防止維護(hù)B中對A的類對象(注意不是實(shí)例對象)的引用更改,因?yàn)楦膖emp會直接導(dǎo)致類A(注意不是類A的對象)結(jié)構(gòu)的變化。 

我們看到了,在Js版本更新的過程中,為了更方便的執(zhí)行這種上下文this的切換以達(dá)到繼承或者更加廣義的目的,增加了call和apply函數(shù)。它們的原理是一樣的,只是參數(shù)不同的版本罷了(一個(gè)可變?nèi)我鈪?shù),一個(gè)必須傳入數(shù)組作為參數(shù)集合)。這里就以call為例子,解釋一下用call實(shí)現(xiàn)的對象冒充繼承。 

JavaScript code?
1
2
3
4
5
6
7
8
9
10
11
12
13
function Rect(width, height){
    this.width = width;
    this.height = height;
    this.area = function(){return this.width*this.height;};
}
function myRect(width, height, name){
    Rect .call(this,width,height);
    this.name = name;
    this.show = function(){
    alert(this.name+” with area:”+this.area());
    }
}


關(guān)于Call方法,官方解釋:調(diào)用一個(gè)對象的一個(gè)方法,以另一個(gè)對象替換當(dāng)前對象。 
call (thisOb,arg1, arg2…) 

這也是一種對象冒充的繼承,其實(shí)在call方法調(diào)用的時(shí)候發(fā)生的事情也是上下文環(huán)境變量this的替換,在myRect函數(shù)體中this肯定是指向類myRect對象的實(shí)例了,然而用這個(gè)this作為上下文環(huán)境變量調(diào)用名字叫Rect方法,即類Rect的構(gòu)造函數(shù)。于是此時(shí)調(diào)用Rect時(shí)候?qū)his的賦值屬性和方法都實(shí)際上是對一個(gè)myRect的對象進(jìn)行。所以說盡管call和apply并不是僅僅為了繼承而新增的方法,但用它們可以模擬繼承。 

對象冒充繼承就是這么一回事,它可以實(shí)現(xiàn)多重繼承,只要重復(fù)做這一套賦值的流程就可以了。不過目前真正大規(guī)模使用得并不多,為什么呢?因?yàn)樗幸粋€(gè)明顯的性能缺陷,這就要說道OO的概念了,我們說對象是成員+成員方法的集合,構(gòu)造對象實(shí)例的時(shí)候,這些實(shí)例只需要擁有各自的成員變量就可以了,成員方法只是一段對變量操作的可執(zhí)行文本區(qū)域而已,這段區(qū)域不用為每個(gè)實(shí)例而復(fù)制一份,所有的實(shí)例都可以共享。現(xiàn)在回到Js利用對象冒充模擬的繼承里,所有的成員方法都是針對this而創(chuàng)建的,也就是所所有的實(shí)例都會擁有一份成員方法的副本,這是對內(nèi)存資源的一種極度浪費(fèi)。其它的缺陷比如說對象冒充無法繼承prototype域的變量和方法就不用提了,筆者認(rèn)為前一個(gè)致命缺陷就已經(jīng)足夠。不過,我們還是需要理解它,特別是父類的屬性和方法是如何繼承下來的原理,對于理解Js繼承很重要。 

(二)原型方式 
第二種繼承方式是原型方式,所謂原型方式的繼承,是指利用了prototype或者說以某種方式覆蓋了prototype,從而達(dá)到屬性方法復(fù)制的目的。其實(shí)現(xiàn)方式有很多中,可能不同框架多少會有一點(diǎn)區(qū)別,但是我們把握住原理,就不會有任何不理解的地方了。看一個(gè)例子(某一種實(shí)現(xiàn)): 

JavaScript code?
1
2
3
4
5
6
7
8
9
10
function Person(){
    this.name = “Mike”;
    this.sayGoodbye = function(){alert(“GoodBye!”);};
}
Person.prototype.sayHello = function(){alert(”Hello!”);};
function Student(){}
Student.prototype = new Person();


關(guān)鍵是對最后一句Student原型屬性賦值為Person類構(gòu)造的對象,這里筆者解釋一下父類的屬性和方法是如何copy到子類上的。Js對象在讀取某個(gè)對象屬性的時(shí)候,總是先查看自身域的屬性列表,如果有就返回否則去讀取prototype域(每個(gè)對象共享構(gòu)造對象的類的prototype域所有屬性和方法),如果找到就返回,由于prototype可以指向別的對象,所以Js解釋器會遞歸的去查找prototype域指向?qū)ο蟮膒rototype域,直到prototype為本身,查找變成了一種循環(huán),就停止,此時(shí)還沒找到就成undefined了。 

這樣看來,最后一句發(fā)生的效果就是將父類所有屬性和方法連接到子類的prototype域上,這樣子類就繼承了父類所有的屬性和方法,包括name、sayGoodbye和sayHello。這里與其把最后一句看成一種賦值,不如理解成一種指向關(guān)系更好一點(diǎn)。這種原型繼承的缺陷也相當(dāng)明顯,就是繼承時(shí)父類的構(gòu)造函數(shù)時(shí)不能帶參數(shù),因?yàn)閷ψ宇恜rototype域的修改是在聲明子類對象之后才能進(jìn)行,用子類構(gòu)造函數(shù)的參數(shù)去初始化父類屬性是無法實(shí)現(xiàn)的,如下所示: 

JavaScript code?
1
2
3
4
5
6
7
8
9
function Person(name){
    this.name = name;
}
function Student(name,id){
    this.id = id;
}
Student.prototype = new Person(this.name);



兩種繼承方式已經(jīng)講完了,如果我們理解了兩種方式下子類如何把父類的屬性和方法“抓取”下來,就可以自由組合各自的利弊,來實(shí)現(xiàn)真正合理的Js繼承。下面是個(gè)人總結(jié)的一種綜合方式: 

JavaScript code?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Person(name){
    this.name = name;
}
Person.prototype.sayHello = function(){alert(this.name+“say Hello!”);};
function Student(name,id){
    Person.call(this,name);
    this.id = id;
}
Student.prototype = new Person();
Student.prototype.show = function(){
    alert(“Name is:”+ this.name+” and Id is:”+this.id);
}


總結(jié)就是利用對象冒充機(jī)制的call方法把父類的屬性給抓取下來,而成員方法盡量寫進(jìn)被所有對象實(shí)例共享的prototype域中,以防止方法副本重復(fù)創(chuàng)建。然后子類繼承父類prototype域來抓取下來所有的方法。如想徹底理清這些調(diào)用鏈的關(guān)系,推薦大家多關(guān)注Js中prototype的constructor和對象的constructor屬性,這里就不多說了。有時(shí)間再總結(jié)總結(jié)。這次就講這些吧,不足之處,還請指正![/
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
ECMAScript:原型鏈 (prototype 與
悟透JavaScript(續(xù))
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

主站蜘蛛池模板: 晋州市| 沽源县| 阿巴嘎旗| 广饶县| 仙居县| 扶余县| 科技| 景泰县| 油尖旺区| 巴中市| 德保县| 宿松县| 皮山县| 洪江市| 杨浦区| 渭南市| 衡南县| 射阳县| 祁连县| 应城市| 武乡县| 南岸区| 逊克县| 富顺县| 朝阳县| 永顺县| 沿河| 漳州市| 福泉市| 同江市| 平和县| 百色市| 麦盖提县| 肥东县| 杭州市| 秭归县| 西安市| 清水河县| 汝州市| 文山县| 新乐市|