要理解原型鏈,繞不開constructor、prototype、__proto__這幾個核心的知識點,它們的關係如下:
上面的圖是一個最簡單的原型鏈,先有一個直觀的認識。下面將圍繞上面3個點一步步對原型鏈抽絲剝繭,最後在來總結究竟什麼是原型鏈,自然就清晰了。
2. 課前預習
再正式進入主題之前,先了解幾個知識點
2.1 函數對象與普通對象
JavaScript 中,萬物皆對象,但對象也是有區別的。分為普通對象和函數對象, Object 、Function 是 JS 自帶的函數對象 。
函數對象<code>//f1,f2,歸根結底都是通過 new Function()的方式進行創建的
function f1(){};//console.log(typeof f1)==function
var f2 = function(){};//同上
var f3 = new Function('str','console.log(str)');//同上/<code>普通對象
<code>var o1 = {}; // console.log(typeof o1) == object
var o2 = new Object();//同上
var o3 = new f1();//同上/<code>
簡單的說,凡是使用 function 關鍵字或 Function 構造函數創建的對象都是函數對象,其他的都是普通對象
2.2 幾個專業術語
顯式原型:prototype隱式原型:__ proto __原型對象:每個函數對象都有一個prototype 屬性,這個屬性指向函數的原型對象3. prototype和contructor
prototype指向函數的 原型對象 ,只有函數或者說函數對象才擁有該屬性。contructor指向原型對象的構造函數。可能很多人對什麼是原型對象比較迷惑,個人是按照下面的模版記得:
原型對象 = 構造函數名.prototype
<code>//Person.prototype就是原型對象
function Person() {}
Person.prototype = {
name: 'Zaxlct',
sayName: function() {
}
}/<code>
3.1 prototype和contructor關係
主要從三個緯度來分析:自定義的構造函數(Person)、Object函數、Function函數
<code>// 可以思考一下打印結果
function Person() {}
console.log(Person.prototype)//[object Object]
console.log(Person.prototype.constructor)//function Person() {}/<code>
3.2 prototype創建時機
在定義函數時自動添加的, 默認值是一個空Object對象
<code>//定義構造函數
function Fn() { // 內部語句: this.prototype = {}
}/<code>
3.3 prototype作用
通過給 Person.prototype 設置屬性和方法之後,Person 的實例都會繼承相應的屬性和方法,所有的實列例共享一份,不會開闢新的空間。prototype用來實現基於原型的繼承與屬性的共享4. proto
JS 在創建對象(不論是普通對象還是函數對象)的時候,都有一個叫做__proto__ 的內置屬性,用於指向創建它的構造函數的原型對象。
由於js中是沒有類的概念,而為了實現繼承,通過 __ proto __ 將對象和原型聯繫起來組成原型鏈,就可以讓對象訪問到不屬於自己的屬性。
4.1 函數和對象的關係
所有函數都是Function的實例(包含Function),所有構造器都繼承了Function.prototype的屬性及方法。
4.2 原型對象間的關係
所有的原型對象__proto__最終指向了Object.prototype(除了Object.prototype的__proto__之外)。
js原型鏈最終指向的是Object原型對象
4.3 proto創建時機
對象的__proto__屬性: 創建對象時自動添加的, 默認值為構造函數的prototype屬性值
<code>function Fn() { }
// 內部語句: this.__proto__ = Fn.prototype
var fn = new Fn() /<code>
4.4 總結
當你new一個構造函數的時候,創建一個函數實例,那麼 『 函數實例.__ proto __ === 該構造函數.prototype 』所有的函數都是由Function構造出來的,那麼 『被構造出來的其他函數.__ proto __ === Function.prototype 』所有的構造函數的原型對象都是由Object構造出來的,那麼 『所有的構造函數.prototype.__ proto __ === Object.prototype 』5. 完整原型鏈結構圖
6. 原型鏈的查找和內存表現
<code>function Person() {
this.test1 = function () {
console.log('test1()')
}
}
console.log(Person.prototype)
Person.prototype.test2 = function () {
console.log('test2()')
}
Object.prototype.test3 = function () {
console.log('test3()')
}
const personObj = new Person()
personObj.test1()//test1
personObj.test2()//test2
personObj.test3()//test3
/<code>
對應到內存中的原型鏈如下圖: