今天小編要跟大家分享的文章是關(guān)于Javascript繼承的常用4種方法。相信很多學(xué)習(xí)web前端開發(fā)技術(shù)的小伙伴在學(xué)習(xí)前端開發(fā)的javascript部分的時候,在面向?qū)ο蟮牟糠志秃茈y走下去了,主要的原因還是邏輯更加復(fù)雜了,需要理解的內(nèi)容比直觀的開發(fā)布局難一點(diǎn)。

成都一家集口碑和實(shí)力的網(wǎng)站建設(shè)服務(wù)商,擁有專業(yè)的企業(yè)建站團(tuán)隊(duì)和靠譜的建站技術(shù),10年企業(yè)及個人網(wǎng)站建設(shè)經(jīng)驗(yàn) ,為成都近千家客戶提供網(wǎng)頁設(shè)計(jì)制作,網(wǎng)站開發(fā),企業(yè)網(wǎng)站制作建設(shè)等服務(wù),包括成都營銷型網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),同時也為不同行業(yè)的客戶提供網(wǎng)站建設(shè)、網(wǎng)站制作的服務(wù),包括成都電商型網(wǎng)站制作建設(shè),裝修行業(yè)網(wǎng)站制作建設(shè),傳統(tǒng)機(jī)械行業(yè)網(wǎng)站建設(shè),傳統(tǒng)農(nóng)業(yè)行業(yè)網(wǎng)站制作建設(shè)。在成都做網(wǎng)站,選網(wǎng)站制作建設(shè)服務(wù)商就選創(chuàng)新互聯(lián)公司。
在面向?qū)ο缶幊汤铮庋b和繼承是比較重要的,這中間,繼承是相對而言比較難理解的,因?yàn)閖avascript的繼承方式比較多,也有不同的優(yōu)缺點(diǎn)。今天小編為大家?guī)磉@篇文章就是來和大家一起說一說Javascript繼承的常用4種方法,希望能夠?qū)δ阌兴鶐椭?/p>
1、原型鏈繼承
核心:將父類的實(shí)例作為子類的原型
缺點(diǎn):父類新增原型方法/原型屬性,子類都能訪問到,父類一變其它的都變了
2、構(gòu)造繼承
基本思想
借用構(gòu)造函數(shù)的基本思想就是利用call或者apply把父類中通過this指定的屬性和方法復(fù)制(借用)到子類創(chuàng)建的實(shí)例中。
因?yàn)閠his對象是在運(yùn)行時基于函數(shù)的執(zhí)行環(huán)境綁定的。也就是說,在全局中,this等于window,而當(dāng)函數(shù)被作為某個對象的方法調(diào)用時,this等于那個對象。
call、apply方法可將一個函數(shù)的對象上下文從初始的上下文改變?yōu)橛蓆hisObj指定的新對象。
所以,這個借用構(gòu)造函數(shù)就是,new對象的時候(new創(chuàng)建的時候,this指向創(chuàng)建的這個實(shí)例),創(chuàng)建了一個新的實(shí)例對象,并且執(zhí)行Parent里面的代碼,而Parent里面用call調(diào)用了Person,也就是說把this指向改成了指向新的實(shí)例,所以就會把Person里面的this相關(guān)屬性和方法賦值到新的實(shí)例上,而不是賦值到Person上面,所以所有實(shí)例中就擁有了父類定義的這些this的屬性和方法。
因?yàn)閷傩允墙壎ǖ絫his上面的,所以調(diào)用的時候才賦到相應(yīng)的實(shí)例中,各個實(shí)例的值就不會互相影響了。
核心:使用父類的構(gòu)造函數(shù)來增強(qiáng)子類實(shí)例,等于是復(fù)制父類的實(shí)例屬性給子類(沒用到原型)
缺點(diǎn):方法都在構(gòu)造函數(shù)中定義,
只能繼承父類的實(shí)例屬性和方法,不能繼承原型屬性/方法,無法實(shí)現(xiàn)函數(shù)復(fù)用,每個子類都有父類實(shí)例函數(shù)的副本,影響性能
3、組合繼承
組合繼承(所有的實(shí)例都能擁有自己的屬性,并且可以使用相同的方法,組合繼承避免了原型鏈和借用構(gòu)造函數(shù)的缺陷,結(jié)合了兩個的優(yōu)點(diǎn),是最常用的繼承方式)
核心:通過調(diào)用父類構(gòu)造,繼承父類的屬性并保留傳參的優(yōu)點(diǎn),然后再通過將父類實(shí)例作為子類原型,實(shí)現(xiàn)函數(shù)復(fù)用
缺點(diǎn):調(diào)用了兩次父類構(gòu)造函數(shù),生成了兩份實(shí)例(子類實(shí)例將子類原型上的那份屏蔽了)
4、寄生組合繼承
核心:通過寄生方式,砍掉父類的實(shí)例屬性,這樣,在調(diào)用兩次父類的構(gòu)造的時候,就不會初始化兩次實(shí)例方法/屬性,避免的組合繼承的缺點(diǎn)
缺點(diǎn):堪稱完美,但實(shí)現(xiàn)較為復(fù)雜
以上就是小編今天為大家分享的關(guān)于web前端學(xué)習(xí)之Javascript繼承的常用4種方法的文章,希望本篇文章能夠?qū)φ趯W(xué)習(xí)web前端技術(shù)的小伙伴們有所幫助。想要了解更多web前端知識記得關(guān)注北大青鳥web培訓(xùn)官網(wǎng)。
文章轉(zhuǎn)載自公眾號:前端研究所
(1)嵌入HTML文件中
一般放在head/head(事實(shí)上可以放在任何位置)中,格式:
script type="text/javascript"
//此處為JavaScript代碼
/script
(2) 定義專門的外部文件
將JavaScript代碼寫在一個獨(dú)立的腳本文件(擴(kuò)展名為.js)中,在頁面中使用時直接導(dǎo)入該腳本文件即可,導(dǎo)入的格式:
script type="text/javascript" src="要導(dǎo)入的js文件.js"/script
(3)除了上面兩種最為常用的方式外,還可以在以下地方定義JavaScript代碼
A、在HTML的元素事件屬性中,比如,按鈕的單擊事件,語法:
input type="button" onclick="javascript:js腳本代碼" /
范例:
B、在超鏈接中定義,語法:
a href="javascript:js腳本代碼" 超鏈接/a
范例:
1.對象的字面量的形式var obj = {} 2.new 的方式來調(diào)用構(gòu)造函數(shù)的形式 Object是個構(gòu)造函數(shù)var obj = new Object(); obj.name = '黃忠' 3.工廠方法 function fn (name) { // 1. 創(chuàng)建一個空對象 var obj = new Object() // 2. 給對象添加屬性和方法 obj.name = name // 3. 返回一個obj對象 return obj} 4.構(gòu)造函數(shù) 帕斯卡命名 第一個單詞的第一個字母大寫,后續(xù)的每一個單詞的第一個字母都大寫通過this動態(tài)的給構(gòu)造函數(shù)添加屬性和方法 function Hero(name, weapon, equipment, blood) { // this 動態(tài)的給對象增加成員 // this 指向了當(dāng)前對象 this.name = name; this.weapon = weapon; this.equipment = equipment; this.blood = blood; this.attack = function () { console.log(this.name + ':攻擊'); } this.run = function () { console.log(this.name + ': 加速跑'); } } var hero1 = new Hero('黃忠', '弓箭', ['頭盔', '靴子'], 100);
Javascript對象定義的幾種方式
一.工廠方式:先創(chuàng)建對象,再向?qū)ο筇砑臃椒ê蛯傩裕忾]后調(diào)用不要使用new操作符創(chuàng)建對象。使用這種方法有很多弊端,把方法定義在工廠函數(shù)內(nèi)部的時候,每次調(diào)用的時候都會產(chǎn)生新的函數(shù)
function factory(name,person,address,time){
var tmp=new Object;
tmp.name=name;
tmp.person=person;
tmp.address=address;
tmp.workTime=function(){
alert("we start to work at" + time);
}
return tmp;
}
var factory1=factory("drugs",100,"huashan Rd",10);
var factory2=factory("TCMdrugs",100,"hongqiao Rd",11);
factory1.workTime();
factory2.workTime();//Here,factory1 and factory2 have different method
對這種問題雖然可以用下面的方式改進(jìn),但是缺乏很好的封裝性
function factory(name,person,address,time){
var tmp=new Object;
tmp.name=name;
tmp.person=person;
tmp.address=address;
tmp.workTime=workTime();
return tmp;
}
function workTime(){
alert("we start to work at" + this.time);
}
二,構(gòu)造函數(shù)方式,在構(gòu)造函數(shù)內(nèi)部不創(chuàng)建對象,使用this關(guān)鍵字,使用時候用new操作符,存在和工廠方式相同的問題,重復(fù)創(chuàng)建函數(shù)。
function counstruct(name,person,address,time){
this.name=name;
this.person=person;
this.address=address;
this.workTime=function(){
alert("we start to work at" + this.time);
};
}
三.原型方式:利用prototype屬性來實(shí)現(xiàn)屬性和方法,可以通過instanceof 檢查對象類型,解決了重復(fù)創(chuàng)建函數(shù)的問題,但不能通過傳遞參數(shù)初始化屬性
function Car(){
}
Car.prototype.color = "red";
Car.prototype.doors = 4;
Car.prototype.mpg = 23;
Car.prototype.showColor = function(){
alert(this.color);
};
var car1 = new Car();
var car2 = new Car();
但是如果遇到下面的情況,又出問題了
Car.prototype.drivers = new Array("mike", "sue");
car1.drivers.push("matt");
alert(car1.drivers); //outputs "mike,sue,matt"
alert(car2.drivers); //outputs "mike,sue,matt"
drivers是指向Array對象的指針,Car的兩個實(shí)例都指向同一個數(shù)組。
四.混合的構(gòu)造函數(shù)/原型方式:針對原型方式的解決方案
function Car(sColor, iDoors, iMpg){
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("mike", "sue");
}
Car.prototype.showColor = function (){
alert(this.color);
};
var car1 = new Car("red", 4, 23);
var car2 = new Car("blue", 3, 25);
car1.drivers.push("matt");
alert(car1.drivers);
alert(car2.drivers);
五.動態(tài)原型方式:這種方式是極力推薦的方式,避免了前面幾種方式所出現(xiàn)的問題,提供了更友好的編碼風(fēng)格
function Car(sColor, iDoors, iMpg){
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("mike", "sue");
if(typeof Car.initialized == "undefined"){
Car.prototype.showColor = function (){
alert(this.color);
};
Car.initialized = true;
}
}
var car1 = new Car("red", 4, 23);
var car2 = new Car("blue", 3, 25);
car1.drivers.push("matt");
alert(car1.drivers);
alert(car2.drivers);
六.混合工廠方式:和工廠方式有些相似,但采用new關(guān)鍵字實(shí)例化,具有和工廠方式相同的弊端,不推薦使用
Javascript的繼承在很多書里面細(xì)致的分了很多種類型和實(shí)現(xiàn)方式,大體上就是兩種:對象冒充、原型方式。這兩種方式各有優(yōu)點(diǎn)和缺陷,這里我給你先列舉出來,再從底層分析區(qū)別:
(一)對象冒充
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的時候,調(diào)用temp相當(dāng)于啟動A的構(gòu)造函數(shù),注意這里的上下文環(huán)境中的this對象是B的實(shí)例,所以在執(zhí)行A構(gòu)造函數(shù)腳本時,所有A的變量 和方法都會賦值給this所指的對象,即B的實(shí)例,這樣子就達(dá)到B繼承了A的屬性方法的目的。之后刪除臨時引用temp,是防止維護(hù)B中對A的類對象(注 意不是實(shí)例對象)的引用更改,因?yàn)楦膖emp會直接導(dǎo)致類A(注意不是類A的對象)結(jié)構(gòu)的變化。
我們看到了,在Js版本更新的過程中,為了更方便的執(zhí)行這種上下文this的切換以達(dá)到繼承或者更加廣義的目的,增加了call和apply函數(shù)。它們的 原理是一樣的,只是參數(shù)不同的版本罷了(一個可變?nèi)我鈪?shù),一個必須傳入數(shù)組作為參數(shù)集合)。這里就以call為例子,解釋一下用call實(shí)現(xiàn)的對象冒充 繼承。
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)用一個對象的一個方法,以另一個對象替換當(dāng)前對象。
call (thisOb,arg1, arg2…)
這也是一種對象冒充的繼承,其實(shí)在call方法調(diào)用的時候發(fā)生的事情也是上下文環(huán)境變量this的替換,在myRect函數(shù)體中this肯定是指向類 myRect對象的實(shí)例了,然而用這個this作為上下文環(huán)境變量調(diào)用名字叫Rect方法,即類Rect的構(gòu)造函數(shù)。于是此時調(diào)用Rect時候?qū)his 的賦值屬性和方法都實(shí)際上是對一個myRect的對象進(jìn)行。所以說盡管call和apply并不是僅僅為了繼承而新增的方法,但用它們可以模擬繼承。
對象冒充繼承就是這么一回事,它可以實(shí)現(xiàn)多重繼承,只要重復(fù)做這一套賦值的流程就可以了。不過目前真正大規(guī)模使用得并不多,為什么呢?因?yàn)樗幸粋€明顯的 性能缺陷,這就要說道OO的概念了,我們說對象是成員+成員方法的集合,構(gòu)造對象實(shí)例的時候,這些實(shí)例只需要擁有各自的成員變量就可以了,成員方法只是一 段對變量操作的可執(zhí)行文本區(qū)域而已,這段區(qū)域不用為每個實(shí)例而復(fù)制一份,所有的實(shí)例都可以共享。現(xiàn)在回到Js利用對象冒充模擬的繼承里,所有的成員方法都 是針對this而創(chuàng)建的,也就是所所有的實(shí)例都會擁有一份成員方法的副本,這是對內(nèi)存資源的一種極度浪費(fèi)。其它的缺陷比如說對象冒充無法繼承 prototype域的變量和方法就不用提了,筆者認(rèn)為前一個致命缺陷就已經(jīng)足夠。不過,我們還是需要理解它,特別是父類的屬性和方法是如何繼承下來的原 理,對于理解Js繼承很重要。
(二)原型方式
第二種繼承方式是原型方式,所謂原型方式的繼承,是指利用了prototype或者說以某種方式覆蓋了prototype,從而達(dá)到屬性方法復(fù)制的目的。 其實(shí)現(xiàn)方式有很多中,可能不同框架多少會有一點(diǎn)區(qū)別,但是我們把握住原理,就不會有任何不理解的地方了。看一個例子(某一種實(shí)現(xiàn)):
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對象在讀取某 個對象屬性的時候,總是先查看自身域的屬性列表,如果有就返回否則去讀取prototype域(每個對象共享構(gòu)造對象的類的prototype域所有屬性 和方法),如果找到就返回,由于prototype可以指向別的對象,所以Js解釋器會遞歸的去查找prototype域指向?qū)ο蟮膒rototype 域,直到prototype為本身,查找變成了一種循環(huán),就停止,此時還沒找到就成undefined了。
這樣看來,最后一句發(fā)生的效果就是將父類所有屬性和方法連接到子類的prototype域上,這樣子類就繼承了父類所有的屬性和方法,包括name、 sayGoodbye和sayHello。這里與其把最后一句看成一種賦值,不如理解成一種指向關(guān)系更好一點(diǎn)。這種原型繼承的缺陷也相當(dāng)明顯,就是繼承時 父類的構(gòu)造函數(shù)時不能帶參數(shù),因?yàn)閷ψ宇恜rototype域的修改是在聲明子類對象之后才能進(jìn)行,用子類構(gòu)造函數(shù)的參數(shù)去初始化父類屬性是無法實(shí)現(xiàn)的, 如下所示:
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繼承。下面是個人總結(jié)的一種綜合方式:
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屬性,這里就不多說了。
我認(rèn)為添加JavaScript代碼的方式有三種:
① 行內(nèi)方式:直接把JavaScript代碼寫在標(biāo)簽中-
div onclick='alert("Hi, 我是JavaScript代碼");'/div
② 內(nèi)嵌方式:在script/script標(biāo)簽中寫入正確的JavaScript代碼,
script type="text/javascript"
alert("Hi, 我是JavaScript代碼");
/script
③ 外部js文件引入:在script/script標(biāo)簽中設(shè)置路徑src屬性,并在其中寫入相應(yīng)的js文件的路徑,但是之后這個script標(biāo)簽里面不可以寫入如何代碼-
script src="js/first.js"/script
script type="text/javascript"
......
/script
當(dāng)前題目:包含javascript方式的詞條
鏈接URL:http://chinadenli.net/article20/dsgojjo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、商城網(wǎng)站、小程序開發(fā)、定制開發(fā)、響應(yīng)式網(wǎng)站、網(wǎng)頁設(shè)計(jì)公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)