程式碼
講解用到的程式碼很簡單,如下
function Foo(){
//屬性和方法
}
var f1 = new Foo();
var f2 = new Foo();
var o1 = new Object();
var o2 = new Object();
複製程式碼
基礎瞭解
一切皆物件,物件又可以分為兩類:
- 普通物件 ,除了函式物件之外的物件都是,包括new函式物件()產生的例項,普通物件沒有prototype,也就沒有繼承和原型鏈一說。
- 函式物件 ,包括兩種:
-
由function創造出來的函式:
function f1() { } // 匿名函式 var f2 = function() { } var f3 = new Function('x','console.log(x)'); // 以上都是函式物件 複製程式碼
-
系統內建的函式物件: Function、Object、Array、String、Number ,Function其實充當了函式物件的構造器,比如Object物件的構造原始碼其實是Function Object() {[native code]}的形式,這一點對於理解原型鏈很重要。
進入正題
上圖從結構上分為例項物件、Functions函式物件、prototype原型物件三部分,圖中f1、f2的原型鏈我特意標成了紅色,Foo的原型鏈為紫色。每個物件都有__proto__
屬性,用於儲存繼承得來的方法和屬性;每個函式物件都有prototype
屬性,用於繼承,將其中定義的屬性和方法傳遞給‘後代’(比如例項化)。
如何實現原型繼承
f1為何有Foo、Object的原型方法,其實就是通過原型鏈繼承。繼承的過程可以表示為f1.__proto__ = Foo.prototype
,即物件.__proto__ = 構造器.prototype
。
new例項實現繼承的過程其實與上面原理相同,new的過程可以拆解為下面幾個步驟:
var temp = {};
temp.__proto__ = Foo.prototype; // 原型繼承
var f1 = Foo.call(temp);
return f1;
複製程式碼
找出原型鏈
1) f1的原型鏈(紅色虛線)。
- f1為普通物件,它的構造器為Foo,以Foo為原型,原型鏈第一鏈為
f1.__proto__ == Foo.prototype
; - Foo.prototype(注意這邊不是Foo)為json物件,即普通物件,構造器為Object,以Object為原型,得出原型鏈第二鏈
Foo.prototype.__proto__ == Object.prototype
; - Object.prototype以Null為原型,原型鏈第三鏈為
Object.prototype.__proto__ == null
;
f1的原型鏈可以用圖形表示:
可以在瀏覽器console列印驗證:
2) Foo的原型鏈(紫色虛線)
- Foo為函式物件,它的構造器為Function,以Function為原型,原型鏈第一鏈為
Foo.__proto__ == Function.prototype
; - Function.prototype為json物件,即普通物件,構造器為Object,以Object為原型,原型鏈第二鏈為
Function.prototype.__proto__ == Object.prototype
; - 最後Object.prototype以Null為原型,原型鏈第三鏈為
Object.prototype.__proto__ == null
;
Foo的原型鏈可以用圖形表示為:
可以在瀏覽器console列印驗證:3)小結
列出兩種原型鏈的目的是:
當js引擎執行物件的屬性或方法時,先查詢物件本身是否存在該方法,如果不存在則會在原型鏈上查詢。
因而f1擁有Foo、Object的原型方法,Foo擁有Function、Object的原型方法。
注意,雖然f1原型鏈其中有一鏈是涉及到函式物件Foo,但f1並不擁有Function的原型方法,因為原型鏈並沒有延伸到Function。
比如下圖中bind是Function的原型方法,f1並沒有擁有。
總結
如何找出一個物件的原型鏈,只需要兩步
- 判斷物件是普通物件還是函式物件,得出物件的構造器
- 物件.proto = 構造器.prototype
關於最上面的圖形,只剩Object和Function的特殊關係和建構函式constructor沒有講到, 瞭解Object和Function的關係,戳這兒~
如果有講不清和講錯了的地方,請幫我指出來,我也跟大家一起在學習中,請輕噴(●ˇ∀ˇ●)