成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript學(xué)習(xí)總結(jié)(五)原型和原型鏈詳解

EscapedDog / 1712人閱讀

摘要:原型對(duì)象內(nèi)部也有一個(gè)指針屬性指向構(gòu)造函數(shù)實(shí)例可以訪問原型對(duì)象上定義的屬性和方法。在創(chuàng)建子類型的實(shí)例時(shí),不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù)。

贊助我以寫出更好的文章,give me a cup of coffee?

2017最新最全前端面試題

私有變量和函數(shù)

在函數(shù)內(nèi)部定義的變量和函數(shù),如果不對(duì)外提供接口,外部是無(wú)法訪問到的,也就是該函數(shù)的私有的變量和函數(shù)。


這樣在函數(shù)對(duì)象Box外部無(wú)法訪問變量colorfn,他們就變成私有的了:

var obj = new Box();
    alert(obj.color);//彈出 undefined
    alert(obj.fn);//同上
靜態(tài)變量和函數(shù)

當(dāng)定義一個(gè)函數(shù)后通過點(diǎn)號(hào) “.”為其添加的屬性和函數(shù),通過對(duì)象本身仍然可以訪問得到,但是其實(shí)例卻訪問不到,這樣的變量和函數(shù)分別被稱為靜態(tài)變量靜態(tài)函數(shù)。


實(shí)例變量和函數(shù)

在面向?qū)ο缶幊讨谐艘恍?kù)函數(shù)我們還是希望在對(duì)象定義的時(shí)候同時(shí)定義一些屬性和方法,實(shí)例化后可以訪問,js也能做到這樣


為實(shí)例變量和方法添加新的方法和屬性

box1中修改了afn,而在box2中沒有改變,由于數(shù)組和函數(shù)都是對(duì)象,是引用類型,這就說明box1中的屬性和方法與box2中的屬性與方法雖然同名但卻不是一個(gè)引用,而是對(duì)Box對(duì)象定義的屬性和方法的一個(gè)復(fù)制。

這個(gè)對(duì)屬性來(lái)說沒有什么問題,但是對(duì)于方法來(lái)說問題就很大了,因?yàn)榉椒ǘ际窃谧鐾耆粯拥墓δ埽菂s又兩份復(fù)制,如果一個(gè)函數(shù)對(duì)象有上千和實(shí)例方法,那么它的每個(gè)實(shí)例都要保持一份上千個(gè)方法的復(fù)制,這顯然是不科學(xué)的,這可腫么辦呢,prototype應(yīng)運(yùn)而生。

基本概念

我們創(chuàng)建的每個(gè)函數(shù)都有一個(gè)prototype屬性,這個(gè)屬性是一個(gè)指針,指向一個(gè)對(duì)象,這個(gè)對(duì)象的用途是包含可以由特定類型的所有實(shí)例共享的屬性和方法。那么,prototype就是通過調(diào)用構(gòu)造函數(shù)而創(chuàng)建的那個(gè)對(duì)象實(shí)例的原型對(duì)象。

使用原型的好處是可以讓對(duì)象實(shí)例共享它所包含的屬性和方法。也就是說,不必在構(gòu)造函數(shù)中添加定義對(duì)象信息,而是可以直接將這些信息添加到原型中。使用構(gòu)造函數(shù)的主要問題就是每個(gè)方法都要在每個(gè)實(shí)例中創(chuàng)建一遍。

JavaScript中,一共有兩種類型的值,原始值和對(duì)象值。每個(gè)對(duì)象都有一個(gè)內(nèi)部屬性 prototype ,我們通常稱之為原型。原型的值可以是一個(gè)對(duì)象,也可以是null。如果它的值是一個(gè)對(duì)象,則這個(gè)對(duì)象也一定有自己的原型。這樣就形成了一條線性的鏈,我們稱之為原型鏈

含義

函數(shù)可以用來(lái)作為構(gòu)造函數(shù)來(lái)使用。另外只有函數(shù)才有prototype屬性并且可以訪問到,但是對(duì)象實(shí)例不具有該屬性,只有一個(gè)內(nèi)部的不可訪問的__proto__屬性。__proto__是對(duì)象中一個(gè)指向相關(guān)原型的神秘鏈接。按照標(biāo)準(zhǔn),__proto__是不對(duì)外公開的,也就是說是個(gè)私有屬性,但是Firefox的引擎將他暴露了出來(lái)成為了一個(gè)共有的屬性,我們可以對(duì)外訪問和設(shè)置。

當(dāng)我們調(diào)用Bro.run()方法時(shí),由于Bro中沒有這個(gè)方法,所以,他就會(huì)去他的__proto__中去找,也就是Browser.prototype,所以最終執(zhí)行了該run()方法。(在這里,函數(shù)首字母大寫的都代表構(gòu)造函數(shù),以用來(lái)區(qū)分普通函數(shù))

當(dāng)調(diào)用構(gòu)造函數(shù)創(chuàng)建一個(gè)實(shí)例的時(shí)候,實(shí)例內(nèi)部將包含一個(gè)內(nèi)部指針(__proto__)指向構(gòu)造函數(shù)的prototype,這個(gè)連接存在于實(shí)例和構(gòu)造函數(shù)的prototype之間,而不是實(shí)例與構(gòu)造函數(shù)之間。


Person的實(shí)例person1中包含了name屬性,同時(shí)自動(dòng)生成一個(gè)__proto__屬性,該屬性指向Person的prototype,可以訪問到prototype內(nèi)定義的printName方法,大概就是這個(gè)樣子的:


 每個(gè)JavaScript函數(shù)都有prototype屬性,這個(gè)屬性引用了一個(gè)對(duì)象,這個(gè)對(duì)象就是原型對(duì)象。原型對(duì)象初始化的時(shí)候是空的,我們可以在里面自定義任何屬性和方法,這些方法和屬性都將被該構(gòu)造函數(shù)所創(chuàng)建的對(duì)象繼承。

那么,現(xiàn)在問題來(lái)了。構(gòu)造函數(shù)、實(shí)例和原型對(duì)象三者之間有什么關(guān)系呢?

構(gòu)造函數(shù)、實(shí)例和原型對(duì)象的區(qū)別

實(shí)例就是通過構(gòu)造函數(shù)創(chuàng)建的。實(shí)例一創(chuàng)造出來(lái)就具有constructor屬性(指向構(gòu)造函數(shù))和__proto__屬性(指向原型對(duì)象),

構(gòu)造函數(shù)中有一個(gè)prototype屬性,這個(gè)屬性是一個(gè)指針,指向它的原型對(duì)象。

原型對(duì)象內(nèi)部也有一個(gè)指針(constructor屬性)指向構(gòu)造函數(shù):Person.prototype.constructor = Person;

實(shí)例可以訪問原型對(duì)象上定義的屬性和方法。

在這里person1和person2就是實(shí)例,prototype是他們的原型對(duì)象。

再舉個(gè)栗子:


可以從程序運(yùn)行結(jié)果看出,構(gòu)造函數(shù)的prototype上定義的方法確實(shí)可以通過對(duì)象直接調(diào)用到,而且代碼是共享的。(可以試一下將Animal.prototype.behavior 中的prototype屬性去掉,看看還能不能運(yùn)行。)在這里,prototype屬性指向Animal對(duì)象。

數(shù)組對(duì)象實(shí)例

再看個(gè)數(shù)組對(duì)象的實(shí)例。當(dāng)我們創(chuàng)建出array1這個(gè)對(duì)象的時(shí)候,array1實(shí)際在Javascript引擎中的對(duì)象模型如下:

var array1 = [1,2,3];

array1對(duì)象具有一個(gè)length屬性值為3,但是我們可以通過如下的方法來(lái)為array1增加元素:

array1.push(4); 

push這個(gè)方法來(lái)自于array1的__proto__成員指向?qū)ο蟮囊粋€(gè)方法(Array.prototye.push())。正是因?yàn)樗械臄?shù)組對(duì)象(通過[]來(lái)創(chuàng)建的)都包含有一個(gè)指向同一個(gè)具有push,reverse等方法對(duì)象(Array.prototype)的__proto__成員,才使得這些數(shù)組對(duì)象可以使用push,reverse等方法。

函數(shù)對(duì)象實(shí)例
function Base() {  
    this.id = "base" 
}   

var obj = new Base(); 

這樣代碼的結(jié)果是什么,我們?cè)贘avascript引擎中看到的對(duì)象模型是:

new操作符具體干了什么呢?其實(shí)很簡(jiǎn)單,就干了三件事情。

var obj  = {};  
obj.__proto__ = Base.prototype;  
Base.call(obj); 
原型鏈

原型鏈:當(dāng)從一個(gè)對(duì)象那里調(diào)取屬性或方法時(shí),如果該對(duì)象自身不存在這樣的屬性或方法,就會(huì)去自己關(guān)聯(lián)的prototype對(duì)象那里尋找,如果prototype沒有,就會(huì)去prototype關(guān)聯(lián)的前輩prototype那里尋找,如果再?zèng)]有則繼續(xù)查找Prototype.Prototype引用的對(duì)象,依次類推,直到Prototype.….Prototype為undefined(Object的Prototype就是undefined)從而形成了所謂的“原型鏈”。

這里,用構(gòu)造器Shape()新建了一個(gè)實(shí)體,然后用它去覆蓋該對(duì)象的原型。





原型繼承

原型繼承:
在原型鏈的末端,就是Object構(gòu)造函數(shù)prototype屬性指向的那個(gè)原型對(duì)象。這個(gè)原型對(duì)象是所有對(duì)象的祖先,這個(gè)老祖宗實(shí)現(xiàn)了諸如toString等所有對(duì)象天生就該具有的方法。其他內(nèi)置構(gòu)造函數(shù),如Function,Boolean,String,DateRegExp等的prototype都是從這個(gè)老祖宗傳承下來(lái)的,但他們各自又定義了自身的屬性和方法,從而他們的子孫就表現(xiàn)出各自宗族的那些特征。

ECMAScript中,實(shí)現(xiàn)繼承的方法就是依靠原型鏈實(shí)現(xiàn)的。



原型鏈的問題:原型鏈雖然很強(qiáng)大,可以用它來(lái)實(shí)現(xiàn)繼承,但它也存在一些問題。其中最主要的問題來(lái)自包含引用類型的值原型。包含引用類型的原型屬性會(huì)被所有實(shí)例共享;而這也正是為什么要在構(gòu)造函數(shù)中,而不是在原型對(duì)象中定義屬性的原因。在通過原型來(lái)實(shí)現(xiàn)繼承時(shí),原型實(shí)際上回變成另一個(gè)類型的實(shí)例。于是,原先的實(shí)例屬性也就變成了原型的屬性。

在創(chuàng)建子類型的實(shí)例時(shí),不能向超類型的構(gòu)造函數(shù)中傳遞參數(shù)。實(shí)際上,應(yīng)該說是沒有辦法在不影響所有對(duì)象實(shí)例的情況下,給超類型的構(gòu)造函數(shù)傳遞參數(shù)。再加上剛剛討論的由于原型中包含引用類型值所帶來(lái)的問題,實(shí)踐中很少會(huì)多帶帶使用原型鏈。

再舉個(gè)栗子:


__ptoto__屬性

__ptoto__屬性(IE瀏覽器不支持)是實(shí)例指向原型對(duì)象的一個(gè)指針,它的作用就是指向構(gòu)造函數(shù)的原型屬性constructor,通過這兩個(gè)屬性,就可以訪問原型里的屬性和方法了。

Javascript中的對(duì)象實(shí)例本質(zhì)上是由一系列的屬性組成的,在這些屬性中,有一個(gè)內(nèi)部的不可見的特殊屬性——__proto__,該屬性的值指向該對(duì)象實(shí)例的原型,一個(gè)對(duì)象實(shí)例只擁有一個(gè)唯一的原型。

    
__proto__屬性和prototype屬性的區(qū)別

prototypefunction對(duì)象中專有的屬性。
__proto__是普通對(duì)象的隱式屬性,在new的時(shí)候,會(huì)指向prototype所指的對(duì)象;
__ptoto__實(shí)際上是某個(gè)實(shí)體對(duì)象的屬性,而prototype則是屬于構(gòu)造函數(shù)的屬性。__ptoto__只能在學(xué)習(xí)或調(diào)試的環(huán)境下使用。

原型模式的執(zhí)行流程

1.先查找構(gòu)造函數(shù)實(shí)例里的屬性或方法,如果有,就立即返回。
2.如果構(gòu)造函數(shù)的實(shí)例沒有,就去它的原型對(duì)象里找,如果有,就立即返回

原型對(duì)象的

構(gòu)造函數(shù)的

綜上,整理一下:


構(gòu)造函數(shù).prototype = 原型對(duì)象
原型對(duì)象.constructor = 構(gòu)造函數(shù)(模板)
原型對(duì)象.isPrototypeof(實(shí)例對(duì)象)   判斷實(shí)例對(duì)象的原型 是不是當(dāng)前對(duì)象
工廠模式
 function createObject(name,age){
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    return obj;
}

工廠模式解決了實(shí)例化對(duì)象大量重復(fù)的問題,但還有一個(gè)問題,那就是根本無(wú)法搞清楚他們到底是哪個(gè)對(duì)象的實(shí)例。
使用構(gòu)造函數(shù)的方法,既解決了重復(fù)實(shí)例化的問題,又解決了對(duì)象識(shí)別的問題。

使用構(gòu)造函數(shù)的方法和工廠模式的不同之處在于:

 1.構(gòu)造函數(shù)方法沒有顯示的創(chuàng)建對(duì)象(new Object());
 2.直接將屬性和方法賦值給this對(duì)象
 3.沒有return 語(yǔ)句

當(dāng)使用了構(gòu)造函數(shù),并且new 構(gòu)造函數(shù)(),那么就在后臺(tái)執(zhí)行了new Object()
函數(shù)體內(nèi)的this代表了new Object()出來(lái)的對(duì)象

1.判斷屬性是在構(gòu)造函數(shù)的實(shí)例里,還是在原型里,可以使用`hasOwnProperty()`函數(shù)
2.字面量創(chuàng)建的方式使用constructor屬性不會(huì)指向?qū)嵗?,而?huì)指向Object,構(gòu)造函數(shù)創(chuàng)建的方式則相反
為什么指向Object?因?yàn)锽ox.prototype = {};這種寫法其實(shí)就是創(chuàng)建了一個(gè)新對(duì)象。
而每創(chuàng)建一個(gè)函數(shù),就會(huì)同時(shí)創(chuàng)建它的prototype,這個(gè)對(duì)象也會(huì)自動(dòng)獲取constructor屬性
3.如果是實(shí)例方法,不同的實(shí)例化,他們的方法地址是不一樣的,是唯一的
4.如果是原型方法,那么他們的地址的共享的

原型擴(kuò)展:詳解js閉包

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/87620.html

相關(guān)文章

  • 詳解js面向?qū)ο缶幊?/b>

    摘要:看下面一個(gè)例子優(yōu)點(diǎn)使用構(gòu)造器函數(shù)的好處在于,它可以在創(chuàng)建對(duì)象時(shí)接收一些參數(shù)。按照慣例,構(gòu)造函數(shù)的函數(shù)名應(yīng)始終以一個(gè)大寫字母開頭,以區(qū)分普通函數(shù)。返回該對(duì)象的源代碼。使您有能力向?qū)ο筇砑訉傩院头椒ā? 基本概念 ECMA關(guān)于對(duì)象的定義是:無(wú)序?qū)傩缘募?,其屬性可以包含基本值、?duì)象或者函數(shù)。對(duì)象的每個(gè)屬性或方法都有一個(gè)名字,而每個(gè)名字都映射到一個(gè)值。 類 在現(xiàn)實(shí)生活中,相似的對(duì)象之間往往都有...

    lolomaco 評(píng)論0 收藏0
  • javaScript原型原型詳解(一)

    摘要:執(zhí)行行代碼,我們可以看到控制臺(tái)打印出來(lái)的結(jié)果如下結(jié)果印證了我們上面講的內(nèi)容指向的構(gòu)造函數(shù)指向的原型對(duì)象原型對(duì)象中指向構(gòu)造函數(shù)。 在javascript中原型和原型鏈機(jī)制是最難懂的部分(沒有之一),同時(shí)也是最重要的部分,在學(xué)習(xí)的過程中你可能認(rèn)認(rèn)真真的看了一遍但還是完全不懂書上說的什么,的確是這樣的,我在學(xué)習(xí)的時(shí)候可是反復(fù)看了4、5遍才初步理解了。 下面我把我的理解總結(jié)了一下希望對(duì)你們有...

    springDevBird 評(píng)論0 收藏0
  • JavaScript代碼復(fù)用模式

    摘要:如下代碼所示,可以使用構(gòu)造函數(shù)來(lái)創(chuàng)建父對(duì)象,這樣做的話,自身的屬性和構(gòu)造函數(shù)的原型的屬性都將被繼承。方法繼承自對(duì)象這是中構(gòu)造函數(shù)鏈的一個(gè)示例。 代碼復(fù)用及其原則 代碼復(fù)用,顧名思義就是對(duì)曾經(jīng)編寫過的代碼的一部分甚至全部重新加以利用,從而構(gòu)建新的程序。在談及代碼復(fù)用的時(shí)候,我們首先可以想到的是繼承性。代碼復(fù)用的原則是: 優(yōu)先使用對(duì)象組合,而不是類繼承 在js中,由于沒有類的概念,因此實(shí)例...

    bergwhite 評(píng)論0 收藏0
  • javascript對(duì)象詳解:__proto__prototype的區(qū)別聯(lián)系

    摘要:當(dāng)這步完成,這個(gè)對(duì)象就與構(gòu)造函數(shù)再無(wú)聯(lián)系,這個(gè)時(shí)候即使構(gòu)造函數(shù)再加任何成員,都不再影響已經(jīng)實(shí)例化的對(duì)象了。此時(shí),對(duì)象具有了和屬性,同時(shí)具有了構(gòu)造函數(shù)的原型對(duì)象的所有成員,當(dāng)然,此時(shí)該原型對(duì)象是沒有成員的。 前言 本篇文章用來(lái)記錄下最近研究對(duì)象的一些心得,做一個(gè)記錄與總結(jié),以加深自己的印象,同時(shí),希望也能給正在學(xué)習(xí)中的你一點(diǎn)啟發(fā)。本文適合有一定JavaScript基礎(chǔ)的童鞋閱讀。原文戳這...

    chavesgu 評(píng)論0 收藏0
  • 詳解javascript的類

    摘要:原文地址詳解的類博主博客地址的個(gè)人博客從當(dāng)初的一個(gè)彈窗語(yǔ)言,一步步發(fā)展成為現(xiàn)在前后端通吃的龐然大物。那么,的類又該怎么定義呢在面向?qū)ο缶幊讨?,類是?duì)象的模板,定義了同一組對(duì)象又稱實(shí)例共有的屬性和方法。這個(gè)等同于的屬性現(xiàn)已棄用。。 前言 生活有度,人生添壽。 原文地址:詳解javascript的類 博主博客地址:Damonare的個(gè)人博客 ??Javascript從當(dāng)初的一個(gè)彈窗語(yǔ)言,一...

    hufeng 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<