構(gòu)造函數(shù)和原型的關(guān)系

1. 基本概念:


“原型屬性”也可以叫做“原型”(prototype):所有函數(shù)都有prototype,我覺得可以理解為python中的類屬性,不需要通過實例,直接用類(es5就是函數(shù)名)可以調(diào)用,下面列舉了三種創(chuàng)建函數(shù)的方法,函數(shù)創(chuàng)建后都有prototype屬性,prototype指向“原型對象”。


// 函數(shù)聲明

function F1() {

};

// 表達(dá)式定義

let F2 = function () {

};

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

let F3 = new Function('n1', 'n2', 'return n1+n2');


console.info(F1.prototype)? ? //F1 {}

console.info(F2.prototype)? ? //F2 {}

console.info(F3.prototype)? ? //anonymous {}


原型對象(prototype所指向的對象):這玩意主要就是用來繼承用的,包含實例的方法和屬性。說白了也就是一個對象,用來定義函數(shù)對象的屬性、方法,默認(rèn)情況下它包含一個constructor屬性,如果你重新定義可以覆蓋constructor屬性。


原型對象與構(gòu)造函數(shù)配合一起,就形成一個類了,然后構(gòu)造函數(shù)接收每次初始化對象的初始值,原型對象就提供類模板。而在其他java、python中都寫在class中,當(dāng)然es6也加入了class;以下的簡單代碼幫助理解上面說的,定義一個動物類,根據(jù)構(gòu)造函數(shù)創(chuàng)造不同的動物,如果需要創(chuàng)建特殊動物,可以繼承然后添加一些特殊屬性、方法再創(chuàng)建。---------總結(jié)es5的類可以用“構(gòu)造函數(shù)+構(gòu)造函數(shù)的prototype”來定義,類的對象使用“new構(gòu)造函數(shù)”來生成。


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

let Animal = function (name) {

? ? this.name = name

}

// 原型對象定義

Animal.prototype.getAnimal = function () {

? ? return this.name

}

// 創(chuàng)建對象,會繼承Animal.prototype

let dog = new Animal('dog')

let cat = new Animal('cat')

console.info(dog.getAnimal())

console.info(cat.getAnimal())



上圖展示了構(gòu)造函數(shù)、原型對象、具體對象的屬性、方法及屬性值。



普通對象與函數(shù)對象:通過函數(shù)對象 new一下可以得到普通對象,把函數(shù)對象理解為類,普通對象為實例。如下代碼加強理解,可以看到函數(shù)對象new完以后生產(chǎn)的對象是object;函數(shù)對象中都有prototype前面已經(jīng)說過了(為什么函數(shù)對象中會有這個屬性以后讀取更深以后再解答)


// Animal函數(shù)對象

let Animal = function (name) {

? ? this.name = name

}

// 原型對象

Animal.prototype.getAnimal = function () {

? ? return this.name

}

// 通過函數(shù)對象創(chuàng)建普通對象

let dog = new Animal('dog')

console.info(typeof dog)? ? //object

總結(jié): 函數(shù)對象通過new Function()可以得到,F(xiàn)unction對象可以構(gòu)造函數(shù)對象。而函數(shù)對象又可以new一個普通對象出來。



__proto__:所有對象都有__proto__這個屬性,這個屬性指向?qū)?yīng)“函數(shù)對象(就理解為類)”的prototype,這也是實現(xiàn)原型鏈的根本,在書中一般都用[[prototype]]。



構(gòu)造函數(shù)和constructor屬性:其實前面的圖已經(jīng)標(biāo)注了,概念后續(xù)補上。



原型鏈:ES中的繼承主要用原型鏈來實現(xiàn),記住了這玩意主要用來實現(xiàn)繼承。其基本思想是:利用原型讓一個引用類型繼承另一個引用類型的屬性和方法(js高級程序設(shè)計說的),還是用以上的例子來說明


let Animal = function (name) {

? ? this.name = name

}

// 原型對象定義

Animal.prototype.getAnimal = function () {

? ? return this.name

}

// 創(chuàng)建對象,會繼承Animal.prototype

let dog = new Animal('dog')

let cat = new Animal('cat')

console.info(dog.valueOf())

console.info(cat.valueOf())

跟上面例子就差了最后console打印部分,我們定義的Animal沒有寫valueof()為什么可以調(diào)用這個方法呢?到底是什么鬼?這就是原型鏈搞的鬼。我再把上面的圖形完善一下


上圖還有兩個屬性的指向沒有畫,第一、Animal的__proto__指向;第二、Animal.prototype的__proto__指向。



這個圖把Animal.prototype的__proto__指向添加了,


圖形說明:


1. Animal.prototype是個普通對象,ES中Object是所有對象的基礎(chǔ)。所有引用類型都繼承了Object;所有函數(shù)的默認(rèn)原型是都Object的實例,因此Animal.prototype的__proto__指向Object.prototype,這個一定要理解。


2. 我們調(diào)用cat.valueOf()解釋器會先找dog實例中有沒有這個方法,沒有就在Animal.prototype中查找,沒有再去Object.prototype中查找。然后就有了cat.valueOf()的運行結(jié)果:Animal { name: 'cat' }。


3. Object構(gòu)造函數(shù)的prototype也指向Object.prototype。



最后把Animal的__proto__指向補完基本就差不多了。



?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容