您好,登錄后才能下訂單哦!
上一篇文章把對象的概念講解了一下,這篇文章要重點(diǎn)解釋最讓大家犯迷糊的一些概念,包括
- 構(gòu)造函數(shù)
- 實(shí)例
- 繼承
- 構(gòu)造函數(shù)的屬性與方法(私有屬性與方法)
- 實(shí)例的屬性與方法(共享屬性與方法)
- prototype(原型)
- __proto__(原型)
構(gòu)造函數(shù)依然是個(gè)函數(shù),用來生成對象。所有的對象都是由構(gòu)造函數(shù)創(chuàng)建的
對象哪來的?構(gòu)造函數(shù)生的。而普通函數(shù)不能生成對象(不孕不育),構(gòu)造函數(shù)可以生成對象(有生育能力)。每個(gè)對象都會有一個(gè)自己對應(yīng)的構(gòu)造函數(shù),但是不代表每個(gè)構(gòu)造函數(shù)都會生(生成實(shí)例),有不會生的構(gòu)造函數(shù),例如Math對象(不孕不育)
console.dir(Array); //數(shù)組的構(gòu)造函數(shù)
console.dir(Function); //函數(shù)的構(gòu)造函數(shù)
console.dir(Object); //對象的構(gòu)造函數(shù)
new Math(); //報(bào)錯(cuò),不能生成實(shí)例
new Window(); //報(bào)錯(cuò),不能生成實(shí)例
唐僧說過一句話,用來解釋構(gòu)造函數(shù)與實(shí)例再合適不過了“人是人他媽生的,妖是妖他媽生的”那這里的人他媽與妖他媽就是構(gòu)造函數(shù)。人與妖其實(shí)是下面要說的概念“實(shí)例”
實(shí)例就是對象,由構(gòu)造函數(shù)生成
平時(shí)用的實(shí)際的東西都是實(shí)例(獲取的DOM元素、聲明的數(shù)組、聲明的函數(shù)、聲明的對象),有時(shí)候需要new關(guān)鍵字生成(不是絕對的)
實(shí)例身上有一個(gè)constructor
屬性,它指向?qū)?yīng)構(gòu)造函數(shù)(生母)
instanceof
運(yùn)算符//實(shí)例
[]; //不用new生成
new Array(); //用new生成
[].constructor===Array; //true
[] instanceof Array; //true
生成的實(shí)例具有構(gòu)造函數(shù)身上的屬性與方法(就像老鼠的兒子會打洞)
一個(gè)對象身上有另一個(gè)對象身上的屬性或方法,這種具有的方式就叫繼承
說到繼承首先想到的就是遺產(chǎn)。老人去世了,在二環(huán)里留了一套四合院,那這套房子歸誰呀?不可能歸我吧,歸我的話我就不用在這吭哧吭哧寫文章了。那也不能歸你吧,歸你了你也不能座這看我吭哧吭哧寫的文章。得歸人家兒子,這個(gè)就是繼承。那從這個(gè)例子中得出幾個(gè)重要信息,繼承者與被繼承者之間是有一定關(guān)系的
,最簡單的就是父子或者母子關(guān)系。
那回到程序中,構(gòu)造函數(shù)就是老人,實(shí)例就是兒子。那實(shí)例的屬性或者方法哪來的?構(gòu)造函數(shù)的,不過它可以繼承過來,這是合理合法的。但是也會有特殊情況,假如老人膝下無子,那這房子怎么辦?充公?不能吧,要你你干么?不過這個(gè)老人有一個(gè)唯一的親人,就是弟弟。那弟弟能否拿到這個(gè)房子呢,應(yīng)該是可以的。再回到程序中,剛才這種情況其實(shí)程序中也存在,就是一個(gè)對象可以有另一個(gè)對象身上的東西。
//arr身上是并沒有push方法,這個(gè)方法來自于構(gòu)造函數(shù)Array,是arr繼承了構(gòu)造函數(shù)身上的這個(gè)方法
const arr=[1,2];
arr.push(3);
console.log(arr); //[1, 2, 3]
//Array對象身上并沒有valueOf方法,這個(gè)方法來自于Object對象,是Array對象繼承了Object對象的這個(gè)方法
Array.valueOf===Object.valueOf; //true
構(gòu)造函數(shù)身上的屬性與方法,只有構(gòu)造函數(shù)能用,實(shí)例不能用
再回到這1個(gè)億的例子中來,這個(gè)老人為啥有個(gè)四合院呢,這位老人原來是個(gè)老兵,立過一等功,戰(zhàn)功赫赫,獲得了無數(shù)勛章。那我問你他的這些榮譽(yù),兒子有么?或者弟弟有么?沒有吧。這個(gè)就是構(gòu)造函數(shù)特有的屬性與方法,實(shí)例身上是沒有的
//構(gòu)造函數(shù)的私有屬性與方法
console.log(Array.name); //Array
console.log(Array.of(5)); //[5]
//實(shí)例不能用
const arr=[]; //實(shí)例
console.log(arr.name); //undefined
arr.of(6); //報(bào)錯(cuò)
##實(shí)例的屬性與方法(共享屬性與共享方法)
實(shí)例身上的屬性與方法,只有實(shí)例能用,構(gòu)造函數(shù)不能用(放在prototype里)
老人有兩個(gè)孩子,這倆孩子跟我學(xué)會了js,又學(xué)會了ES6,現(xiàn)在在百度上班做開發(fā),這你說扯不扯,我都快編不下去了。那這些技能老人會么,他不會。所以這個(gè)就叫實(shí)例的屬性與方法,只能實(shí)例去用,構(gòu)造函數(shù)用不了
//實(shí)例的方法
const arr=[1,2,3];
console.log(arr.concat(['a','b'])); //[1, 2, 3, "a", "b"]
Array.concat(['a','b'])); //報(bào)錯(cuò)。你的就是你的,我的就是我的,不能互用。就跟媳婦是一樣
//但構(gòu)造函數(shù)可以間接用
console.log(Array.prototype.concat(['a','b'])); //["a", "b"]
1、構(gòu)造函數(shù)身上的一個(gè)屬性,它的類型為對象,這個(gè)屬性的值就是原型
2、這個(gè)對象里放的屬性與方法,就是構(gòu)造函數(shù)的共享屬性與共享方法,所有實(shí)例都能用
還得回到那一個(gè)億的例子里,我們說兒子能繼承老子的遺產(chǎn),為什么呢?因?yàn)樗袀€(gè)神器叫戶口本,國家給發(fā)的,能證明他們是父子關(guān)系。你去辦手續(xù)的時(shí)候肯定要拿著戶口本。現(xiàn)在都得要證件,當(dāng)然有的時(shí)候你可能需要到派出所開個(gè)證明,證明你就是你。雖然有點(diǎn)扯哈,但是有真實(shí)發(fā)生過,如果派出所不給你證明,那你就不是你。回到程序中,雖然你知道實(shí)例是構(gòu)造函數(shù)生的,那實(shí)例就能有構(gòu)造函數(shù)身上的方法,為什么呢?其實(shí)他們也有證,跟戶口本一樣,這個(gè)證就是prototype
//prototype 原型
console.log(Array.prototype); //數(shù)組的原型對象
//如果把原型上的方法刪除了,那實(shí)例就不能用了。證明原型里放的屬性與方法都是實(shí)例的屬性與方法
const arr=[];
Array.prototype.push=null;
arr.push(6); //報(bào)錯(cuò)
1、這個(gè)屬性是瀏覽器自己部署的,到了ES6也沒有正式寫入標(biāo)準(zhǔn)里,建議大家不要用它,用
Object.getPrototypeOf()
方法替代
2、它也是指原型對象,與prototype
一樣。但是有區(qū)別:歸屬不同,prototype
是函數(shù)身上的屬性,__proto__
是對象身上的屬性
這個(gè)屬性與prototype
屬性往往讓大部分人都百思不得其解,看得是一頭霧水,腦袋擰成了麻花,網(wǎng)上的資料是一堆一堆,但往往大家看得是一愣一愣。其實(shí)這倆東西很簡單,是一道推算題,首先,你要明白原型的結(jié)果只有一個(gè),就是構(gòu)造函數(shù)的prototype
屬性的值。那為什么瀏覽器看熱鬧不嫌事大,給我們找麻煩,又部署了一個(gè)__proto__
呢?其實(shí)瀏覽器也是好心,但沒成想辦了壞事。在沒有這個(gè)屬性以前,只能從函數(shù)身上找到原型。為了能從實(shí)例對象身上也能找到原型,瀏覽器就部署了這個(gè)屬性。以字符串為例推算如下:
?
字符串構(gòu)造函數(shù)的原型放在String.prototype
里。那現(xiàn)在我能否通過實(shí)例找到這個(gè)原型呢?也就是str ? ===String.prototype
const str=new String('kaivon');
console.dir(str); //打印出實(shí)例,點(diǎn)開后看到__proto__
?
要通過實(shí)例找到原型的話,首先要通過實(shí)例找到構(gòu)造函數(shù)(因?yàn)樵驮跇?gòu)造函數(shù)身上)。前面有說過,實(shí)例身上都有一個(gè)屬性叫constructor
,這個(gè)就指向構(gòu)造函數(shù)
console.log(str.constructor===String); //true 通過實(shí)例找到了構(gòu)造函數(shù)
?
那找到了構(gòu)造函數(shù),原型不就放在構(gòu)造函數(shù)身上么?所以變成了這樣
console.log(str.constructor.prototype===String.prototype); //true
?
到這里就推出來如何通過實(shí)例找到原型,但是這么寫是不是有點(diǎn)長呢?天空一聲巨響,__proto__
閃亮登場,瀏覽器為了簡化操作,就讓__proto__
等于constructor.prototype
,也就是變成下面這樣
console.log(__proto__===constructor.prototype); //true
?
所以整個(gè)語句其實(shí)就可以變成這樣
console.log(str.__proto__===String.prototype); //true
?
到這里就明白了吧,再總結(jié)一下
prototype
屬性是構(gòu)造函數(shù)身上的,指向原型__proto__
屬性是對象身上的,指向原型- 實(shí)例的.
__proto__
===構(gòu)造函數(shù).prototype
?
現(xiàn)在是不是恍然大悟、如夢初醒、豁然開朗,但是我不得不澆你一頭冷水啊,還沒有完,看下面
console.dir(String);//打印出構(gòu)造函數(shù),點(diǎn)開也看到了__proto__
?
剛才不是說這玩意是實(shí)例身上的么,現(xiàn)在怎么跑到構(gòu)造函數(shù)身上了?童話里都是騙人的嗎?別急,構(gòu)造函數(shù)是函數(shù)么?函數(shù)是對象么?是吧,這就對了。其實(shí)上面的推理題都好說,都簡單。大家弄不懂的是在這。網(wǎng)上的文章就在這里讓你的麻花越擰越緊。構(gòu)造函數(shù)是函數(shù),是函數(shù)它就是對象,__proto__
既然是對象身上的,那這個(gè)構(gòu)造函數(shù)身上就一定會有。點(diǎn)開__proto__
看一下
?
里面的內(nèi)容不應(yīng)該是String
原型的內(nèi)容么?好像不是哎,這就×××了,剛搞清楚的東西現(xiàn)在全亂了。別急,記住那句話__proto__
永遠(yuǎn)指向?qū)嵗龑ο髮?yīng)的構(gòu)造函數(shù)的prototype
,那就先看實(shí)例對象是誰。我們點(diǎn)開的這個(gè)String
它是什么?它是構(gòu)造函數(shù),它的類型是個(gè)函數(shù)。雖然它是一個(gè)構(gòu)造函數(shù),但在這里它就是一個(gè)實(shí)例對象,并且它的類型是函數(shù),所以它是Function
構(gòu)造函數(shù)的實(shí)例,那Function
的實(shí)例對象身上的__proto__
不應(yīng)該指向Function
的prototype
么?所以這里面的內(nèi)容為Function
對象的原型
console.log(String.__proto__===Function.prototype); //true
?
接著看,這里還有一個(gè)__proto__
?
真是害怕什么來什么呀!這是__proto__
來自于Function
的prototype
,它是個(gè)原型對象,原型對象的數(shù)據(jù)類型當(dāng)然為對象了,所以它是Object
構(gòu)造函數(shù)的實(shí)例,那Object
的實(shí)例對象身上的__proto__
不應(yīng)該指向Object
的prototype
么,所以點(diǎn)開這個(gè)__proto__
里面的內(nèi)容是Object.prototype
的值
?
console.log(String.__proto__.__proto__===Object.prototype); //true
?
因?yàn)?code>Object已經(jīng)是頂層對象了,所以在它的prototype
里不會再出現(xiàn)__proto__
了,但是有人說Object
其實(shí)還有繼承,繼承于null
。但是我不太認(rèn)同這種說法,__proto__
的值是個(gè)對象類型數(shù)據(jù),而Object
已經(jīng)是頂層對象了,它原型對象的__proto__
肯定沒有值了,在ECMAScript
中null
的數(shù)據(jù)類型又為對象,所以就呼應(yīng)上了,而不是繼承于null
。
Object.prototype.__proto__===null; //true
?
到這里我把面向?qū)ο螽?dāng)中關(guān)鍵的一些概念算是說清楚了,下一篇文章來說一下真正的面向?qū)ο蟾拍睿?/p>
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。