圖文解說 Javascript中 原型和原型鏈 構(gòu)造函數(shù) 組合使用方法
原型和原型鏈
原型和原型鏈?zhǔn)乔岸吮容^重要的概念,也比較繞,很多人都搞不明白。剛好今天有人問我索性就寫篇文章整理一下。
首先來說一下什么是原型、原型鏈和構(gòu)造函數(shù)。
原型:JS中的對象都包含了一個(gè)prototype的內(nèi)部屬性,這個(gè)屬性所對應(yīng)的就是該對象的原型。
原型鏈:原型鏈?zhǔn)鞘怯幸恍┯脕砝^承和共享屬性的對象組成的對象鏈。并且原型鏈的長度是有限的。
構(gòu)造函數(shù):原型對象包含一個(gè)constructor屬性,對應(yīng)創(chuàng)建所有指向該原型的實(shí)例的構(gòu)造函數(shù)。
function Super(){};
function Middle(){};
function Sub(){};
Middle.prototype = new Super();
Sub.prototype = new Middle();
var suber = new Sub();
接下來說一下 prototype 和 proto
所有對象都有proto屬性指向該對象的原型。
所有函數(shù)對象除了有proto屬性之外還有prototype屬性。因?yàn)楹瘮?shù)也是對象,所以有proto,但同時(shí)函數(shù)這一對象類型比較特殊,所以還有prototype。
一、構(gòu)造函數(shù)
構(gòu)造函數(shù)其實(shí)就是一個(gè)普通函數(shù),只是我們?yōu)榱藚^(qū)分普通函數(shù),通常建議構(gòu)造函數(shù)name首字母大寫;
function Foo(){
}
構(gòu)造函數(shù)調(diào)用:
function Foo(){
console.log(1) // 1
}
Foo(); // 1
二、原型
JavaScript中數(shù)據(jù)類型分類基本數(shù)據(jù)類型與引用數(shù)據(jù)類型
- 基本數(shù)據(jù)類型:Number,String,Boolean,Undefined,Null,Symbol。
- 引用數(shù)據(jù)類型:Object,F(xiàn)unction,Date,Array,RegExp等。
基本類型中除了undefined與null之外,任意數(shù)字,字符,布爾以及symbol值都有__proto__屬性,以字符串為例,我們打印它的__ptoto__并展開
所有的對象都有__ptoto__屬性,而字符串居然也有__proto__屬性,__proto__是一個(gè)訪問器屬性,它指向創(chuàng)建它的構(gòu)造函數(shù)的原型prototype。還記得前面做杯子的構(gòu)造函數(shù)嗎?每實(shí)例個(gè)杯子其實(shí)只有直徑與高度屬性,但通過實(shí)例的__proto__屬性我們找到了構(gòu)造函數(shù)CupCustom的原型prototype,從而成功訪問了prototype上的color屬性。
function Person(){}
// 為原型對象添加方法
Person.prototype.sayName = function(){ alert(this.name);}
prototype:是函數(shù)的一個(gè)屬性(每個(gè)函數(shù)都有一個(gè)prototype屬性),這個(gè)屬性是一個(gè)指針,指向一個(gè)對象。它是顯示修改對象的原型的屬性。
__proto__:是一個(gè)對象擁有的內(nèi)置屬性(請注意:prototype是函數(shù)的內(nèi)置屬性,__proto__是對象的內(nèi)置屬性),是JS內(nèi)部使用尋找原型鏈的屬性。
function Foo(){
}
Foo.prototype.myName = "你好" // 原型
const foo = new Foo();
foo.__proto__ // 原型鏈接
prototype 屬性就被自動創(chuàng)建了
從上面這張圖可以發(fā)現(xiàn),F(xiàn)oo 對象有一個(gè)原型對象 Foo.prototype,其上有兩個(gè)屬性,分別是 constructor 和 __proto__,其中 __proto__ 已被棄用。
構(gòu)造函數(shù) Foo 有一個(gè)指向原型的指針,原型 Foo.prototype 有一個(gè)指向構(gòu)造函數(shù)的指針 Foo.prototype.constructor,這就是一個(gè)循環(huán)引用,即:
Foo.prototype.constructor === Foo; // true
三、原型鏈
當(dāng)我們在瀏覽器中打印 obj 時(shí)你會發(fā)現(xiàn),在 obj 上居然還有一個(gè) __proto__ 屬性,那么看來之前的疑問就和這個(gè)屬性有關(guān)系了。
其實(shí)每個(gè) JS 對象都有 __proto__ 屬性,這個(gè)屬性指向了原型。這個(gè)屬性在現(xiàn)在來說已經(jīng)不推薦直接去使用它了,這只是瀏覽器在早期為了讓我們訪問到內(nèi)部屬性 [[prototype]] 來實(shí)現(xiàn)的一個(gè)東西。
- Object 是所有對象的爸爸,所有對象都可以通過 __proto__ 找到它。
- Function 是所有函數(shù)的爸爸,所有函數(shù)都可以通過 __proto__ 找到它。
- 函數(shù)的 prototype 是一個(gè)對象。
- 對象的 __proto__ 屬性指向原型,__proto__ 將對象和原型連接起來組成了原型鏈。
看完這張圖,我再來解釋下什么是原型鏈吧。其實(shí)原型鏈就是多個(gè)對象通過 __proto__ 的方式連接了起來。為什么 xialuo 可以訪問到 sayHi 函數(shù),還能訪問eat函數(shù),最后toString等等,就是因?yàn)?xialuo 通過原型鏈__proto__找到了 toString 等函數(shù)。