摘要:原型對(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ú)法訪問變量color和fn,他們就變成私有的了:
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中修改了a和fn,而在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,Date和RegExp等的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ū)別
prototype是function對(duì)象中專有的屬性。
__proto__是普通對(duì)象的隱式屬性,在new的時(shí)候,會(huì)指向prototype所指的對(duì)象;
__ptoto__實(shí)際上是某個(gè)實(shí)體對(duì)象的屬性,而prototype則是屬于構(gòu)造函數(shù)的屬性。__ptoto__只能在學(xué)習(xí)或調(diào)試的環(huán)境下使用。
1.先查找構(gòu)造函數(shù)實(shí)例里的屬性或方法,如果有,就立即返回。
2.如果構(gòu)造函數(shù)的實(shí)例沒有,就去它的原型對(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
摘要:看下面一個(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ì)象之間往往都有...
摘要:執(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ì)你們有...
摘要:如下代碼所示,可以使用構(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í)例...
摘要:當(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ǔ)的童鞋閱讀。原文戳這...
摘要:原文地址詳解的類博主博客地址的個(gè)人博客從當(dāng)初的一個(gè)彈窗語(yǔ)言,一步步發(fā)展成為現(xiàn)在前后端通吃的龐然大物。那么,的類又該怎么定義呢在面向?qū)ο缶幊讨?,類是?duì)象的模板,定義了同一組對(duì)象又稱實(shí)例共有的屬性和方法。這個(gè)等同于的屬性現(xiàn)已棄用。。 前言 生活有度,人生添壽。 原文地址:詳解javascript的類 博主博客地址:Damonare的個(gè)人博客 ??Javascript從當(dāng)初的一個(gè)彈窗語(yǔ)言,一...
閱讀 1008·2021-11-23 09:51
閱讀 3508·2021-11-22 12:04
閱讀 2753·2021-11-11 16:55
閱讀 3009·2019-08-30 15:55
閱讀 3263·2019-08-29 14:22
閱讀 3383·2019-08-28 18:06
閱讀 1271·2019-08-26 18:36
閱讀 2152·2019-08-26 12:08