日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Javascript原型链

發(fā)布時間:2023/11/27 生活经验 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Javascript原型链 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

這是關(guān)于原型鏈的一系列的現(xiàn)象與原理的解釋以及例子 【轉(zhuǎn)載請注明出處與地址】 分成4個部分闡述: 1.如何創(chuàng)建一個對象 2.使用原型鏈prototype實(shí)現(xiàn)對象的繼承. 3.原型鏈上屬性和方法的聯(lián)系與規(guī)則 4.深入剖析原型鏈。 一、如何創(chuàng)建一個對象: 1.使用關(guān)鍵字new創(chuàng)建。 var obj=new Object; 或者 function c() {} var obj=new c(); 2.使用花括號創(chuàng)建。 var obj={}; 我們知道,function是定義一個函數(shù),里面的var 都是局部變量,那么如何聲明一個對象的屬性和方法呢。秘密就在于this關(guān)鍵字。在函數(shù)內(nèi)部使用this關(guān)鍵字,就相當(dāng)于是對象的屬性和方法的聲明這個變量是存在的。具體的例子如下: function a() { this.a=1; this.get=function() { return this.a; } } 那么只要使用用var obj =new a();即創(chuàng)建一個對象的實(shí)例,里面就包括function里面的this屬性和方法的就會直接拷貝到對象變量obj上。直接使用a.a的方法即可調(diào)用相應(yīng)的屬性和方法。 但是注意,除非實(shí)例化function a(),否則無法調(diào)用里面的this關(guān)鍵字指向的屬性以及方法。 因?yàn)榇藭rthis上定義的屬性以及方法類似于C++/JAVA等面向?qū)ο舐暶鞯膶傩砸约胺椒āR虼?#xff0c;這種定義函數(shù)的方法也被稱為JS的構(gòu)造函數(shù)。 二、使用原型鏈prototype實(shí)現(xiàn)對象的繼承. 所有函數(shù)function都有一個默認(rèn)的屬性prototype,通過用typeof函數(shù)測試我們可以看到prototype是一個對象。 alert(typeof(a.prototype)); 結(jié)果: 那么這個prototype的屬性到底有什么用呢~? 既然是一個對象那么賦值的時候就當(dāng)然是付給prototype一個實(shí)例了。事實(shí)上,只要把一個實(shí)例賦給prototype這個屬性,那么這個function就具有這個實(shí)例的屬性和方法。相當(dāng)于我們常說的繼承。請看下面的代碼: function a() { this.ia=1; this.get=function() { return this.ia; } } function b() //b構(gòu)造函數(shù) { this.ic=10; this.getfatherclass=function() { return this.ic; } } b.prototype=new a();//繼承實(shí)例。 var obj =new b();//實(shí)例化函數(shù)b alert(obj.get()); 就是這么簡單的邏輯,我們就是使用對象b實(shí)例化的obj,輸出繼承了父類a的方法get。輸出父類a里面的屬性ia。大家可以看到,這樣就輕松地實(shí)現(xiàn)了繼承。 那如果a又繼承另外一個對象x怎么辦? 答案當(dāng)然是b會繼承a所繼承的所有東西。而他們的關(guān)系就像用prototype屬性連起來一樣。所以我們可以看成也是一個由prototype連接而成的鏈表,人稱原型鏈。 三、原型鏈上屬性和方法的聯(lián)系與規(guī)則 首先我們明確一個概念,原型鏈就是一串好像用屬性prototype連接而成的,每個節(jié)點(diǎn)具有屬性和方法甚至函數(shù)過程的鏈。這種鏈?zhǔn)浇Y(jié)構(gòu)我們無疑可以發(fā)現(xiàn)一個很重要的問題----鏈上的節(jié)點(diǎn)之間發(fā)生屬性或者方法重名怎么辦?下面我們從讀和寫兩方面來解析這條原型鏈的屬性和方法的使用過程。 讀: 從上面的例子里,alert(obj.get())輸出的結(jié)果是什么呢,如果運(yùn)行過一次,我們可以發(fā)現(xiàn)輸出的結(jié)果是1. 但是我們可以看到,構(gòu)造函數(shù)b定義的時候是沒有g(shù)et的方法的,同時,get方法調(diào)用的屬性ia也是b中不存在的,那么我們在擁有prototype繼承的構(gòu)造函數(shù)所實(shí)例化的對象是如何調(diào)用屬性和方法的呢。 結(jié)論是:對于調(diào)用實(shí)例化某一構(gòu)造函數(shù)的對象的方法或者屬性的時候,js會在原型鏈最結(jié)尾的點(diǎn),也就是C++/JAVA上所描述的子類,上述例子中的b函數(shù)上,查找是否有所需要的方法或者屬性,如果找不到的話,就會根據(jù)賦值給prototype的父節(jié)點(diǎn)對象,父構(gòu)造函數(shù)上查找對應(yīng)的屬性和方法,就這樣按照這種規(guī)則查找出對應(yīng)名稱的屬性或方法。如果鏈上節(jié)點(diǎn)都不存在的話,當(dāng)然就會輸出undefined。 如果子節(jié)點(diǎn)有該屬性或者方法,同時父節(jié)點(diǎn)也有的時候,當(dāng)然會優(yōu)先考慮子節(jié)點(diǎn)的,這也類似于C++/JAVA上所描述的覆蓋的概念,子類的屬性或者方法覆蓋父類的。 而在上述例子中,get方法調(diào)用了一個this.ia,那么查找此此元素的時候,也會遵循上訴的原則,先查找構(gòu)造函數(shù)b上是否有屬性ia,沒有的話再查找a上的構(gòu)造函數(shù)上的屬性ia。最后輸出結(jié)果1。如果我們在構(gòu)造函數(shù)b上添加一個屬性this.ia=2,那么結(jié)果會如上述結(jié)論所說輸出2. 寫: 我們都知道,new操作會建立一個和構(gòu)造函數(shù)一模一樣的副本,開辟一個空間存放對象。但是我們從上面的操作可以看到,對于函數(shù)鏈上的屬性,都可以被各個實(shí)例所訪問,那么,js在實(shí)例化有prototype繼承的構(gòu)造函數(shù)的時候,是把鏈上的節(jié)點(diǎn)都實(shí)例化一次,還是被所有實(shí)例所共享呢?下面我們看下面例子。 function a() { this.ia=1; this.get=function() { return this.ia; } } function b() //b構(gòu)造函數(shù) { this.ic=10; this.getfatherclass=function() { return this.ic; } } b.prototype=new a();//繼承實(shí)例。 var obj1 =new b();//實(shí)例化函數(shù)b var obj2 =new b();//實(shí)例化函數(shù)b alert(obj1.ia);//輸出1,因?yàn)樗歉割恆中的ia alert(obj2.ia);//輸出1,因?yàn)樗歉割恆中的ia obj1.ia=2; alert(obj1.ia);//輸出2,因?yàn)閷懖僮鲿趯?shí)例對象建立一個副本ia并且賦值2,無修改其原型鏈上的父節(jié)點(diǎn)。 alert(obj2.ia);//輸出還是1,因?yàn)樗歉割恆中的ia b.prototype.ia=3;//修改原型鏈上的屬性ia。 alert(obj1.ia);//輸出2,因?yàn)橐呀?jīng)在實(shí)例上建立了副本,所以優(yōu)先讀取副本。 alert(obj2.ia);//輸出3,因?yàn)樽宇恇中不存在,所以還是查找父節(jié)點(diǎn)(prototype對象上的對象)上的ia,由于父節(jié)點(diǎn)上的ia已經(jīng)被修改成3,所以輸出3. 上面的例子說明了2件事: 1.寫操作并不是直接查找原型鏈上的屬性,然后更改他,而是直接在實(shí)例上創(chuàng)建在一個同名對象。由于實(shí)例上已經(jīng)存在這個屬性,所以下次讀取的時候優(yōu)先讀取這個已存在的,相當(dāng)于原型鏈上的原屬性被覆蓋(但是還是存在的)。 2.Prototype鏈上的節(jié)點(diǎn)(父類)都是被子類實(shí)例化后的對象所共享,也就是只有唯一的一個對象prototype,因此當(dāng)我們修改b.prototype.ia=3;/后,obj2輸出的也是3,說明他是被其他沒有創(chuàng)建ia屬性副本的實(shí)例所共享的。 這樣我們就清晰了,原型鏈只有一條,并且不會因?yàn)樽宇悓?shí)例化和把鏈上的節(jié)點(diǎn),屬性與方法都實(shí)例化,他將被所有子類的實(shí)例化對象所共享。 而這個原型鏈上的父類是準(zhǔn)讀不準(zhǔn)寫(通過子類實(shí)例化對象改變鏈上節(jié)點(diǎn)的屬性與方法)。一旦你的實(shí)例化對象進(jìn)行和父類屬性與方法同名的寫操作時,就會在實(shí)例化對象上建立對應(yīng)的副本,同時進(jìn)行寫操作,此時這個實(shí)例也覆蓋了原型鏈上的這個屬性和方法。這種方法很好的保護(hù)了原型鏈上節(jié)點(diǎn)的共享性,不用擔(dān)心不小心被其他實(shí)例所修改。這樣大大地節(jié)省了內(nèi)存,可以在頻繁的對象創(chuàng)建中,有效地減少了內(nèi)存空間的使用。 當(dāng)然可以通過函數(shù)b上的prototype對象來修改鏈上的屬性與方法,這樣就可以做到一改全改,讓子類共享的屬性發(fā)生改變。如上面的 b.prototype.ia=3;操作。 這種做法也衍生出一種叫做延時綁定的思想,在使用的時侯才進(jìn)行屬性和方法的綁定,這種行為是可以通過原型鏈、prototype這個屬性實(shí)現(xiàn)的。這樣可以很方便地應(yīng)用到你的編程中,但是注意,這種方法還是弊大于利的,因?yàn)榭梢栽谌魏蔚胤竭M(jìn)行重綁定。所以程序者也許不知道在何時進(jìn)行了綁定,使得代碼很混亂,同時在大代碼量的情況下,照成不可預(yù)料的結(jié)果。因此,延時綁定必須慎用。 四、深入剖析原型鏈。 上面說到,原型鏈?zhǔn)怯蓀rototype連在一起的,事實(shí)上這種說法是不嚴(yán)謹(jǐn),甚至可以說是錯誤的,因?yàn)閜rototype是一個對象,并且實(shí)例是沒有prototype這個屬性的,但是,有比prototype更好的,用來表現(xiàn)原型鏈的東西,這是對象實(shí)例后的一個私有屬性,ie下是不可訪問的,但是用firefox是可以查看的,它才是真正的作為實(shí)例在原型鏈上查找屬性與方法的一個類似指針的屬性。可以這么說,prototype是函數(shù)所有的,而__proto__是實(shí)例化的對象存在的屬性。我們常把這個__proto__指向的原型成為父原型。因?yàn)閜rototype是一個對象的實(shí)例,所以原型也有父原型。下面給出一段例子來解釋這個現(xiàn)象。 function a() { this.ia=1; this.get=function() { return this.ia; } } function b() //b構(gòu)造函數(shù) { this.ic=10; this.getfatherclass=function() { return this.ic; } } b.prototype=new a();//繼承實(shí)例。 alert(a instanceof Function);//a是Function的實(shí)例; alert(a.__proto__ === Function.prototype);//a的父原型指向到Function的原型; alert(b.__proto__ === Function.prototype);//a的父原型指向到Function的原型 var obj =new b();//實(shí)例化函數(shù)b alert(typeof(obj.__proto__));//輸出obejct,說明是一個對象 alert(obj instanceof Object);//ture.obj是其中一個對象 alert(obj.__proto__===b.prototype);//ture。因?yàn)開_prototype指向父原型 alert(obj.__proto__.__proto__===a.prototype);//ture。因?yàn)開_prototype指向父原型 alert(obj.__proto__.__proto__.__proto__===Object.prototype);//ture。因?yàn)開_prototype指向父原型 alert(Object.prototype.__proto__);//null。因?yàn)镺bject的原型是所有父原型的頂端,它不再具有父原型; alert(Function instanceof Object);//Function是Object的實(shí)例; alert(Function.__proto__ === Function.prototype);//Function的父原型指向到Function的原型; alert(Function.prototype.__proto__ === Object.prototype);//Function的原型的父原型指向到Object的原型 alert(Object.__proto__ === Function.prototype);//Object的父原型指向到Function的原型; 從上面的例子我們再也清晰不過了,實(shí)例查找原型鏈的時候使用的__proto__ 這個私有屬性,通過這個屬性一層一層地遍歷原型鏈,而原型鏈的最終父原型是Object.prototype,它是所有實(shí)例的父原型,只要修改這個父原型,那么所有的實(shí)例都將用到修改的屬性。 同時。Function.prototype是所有函數(shù)的父原型,而它Function.prototype的父原型也是Object.prototype。到了這里,我們可以清晰地看到一個實(shí)例后面的原型鏈的全貌了。 ?

轉(zhuǎn)載于:https://www.cnblogs.com/si-ren/archive/2010/12/29/2447674.html

總結(jié)

以上是生活随笔為你收集整理的Javascript原型链的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。