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