原型鏈 原型鏈 引入從Object和Function開始 Object和Function都作為JS的自帶函數,Object繼承自己,Funtion繼承自己,Object和Function互相是繼承對方,也就是說Object和Function都既是函數也是對象。 12 console.log(Func ...
原型鏈
引入從Object和Function開始
Object和Function都作為JS的自帶函數,Object繼承自己,Funtion繼承自己,Object和Function互相是繼承對方,也就是說Object和Function都既是函數也是對象。
1
|
console.log(Function instanceof Object); // true
|
Object 是 Function的實例,而Function是它自己的實例
1
|
console.log(Function.prototype); // ƒ () { [native code] }
|
普通對象和函數對象
JavaScript 中,萬物皆對象!但對象也是有區別的。分為普通對象和函數對象,Object 、Function 是 JS 自帶的函數對象。下麵舉例說明
1
|
var o1 = {};
|
在上面的例子中 o1 o2 o3 為普通對象,f1 f2 f3 為函數對象。怎麼區分,其實很簡單,凡是通過 new Function() 創建的對象都是函數對象,其他的都是普通對象。f1,f2,歸根結底都是通過 new Function()的方式進行創建的。Function Object 也都是通過 New Function()創建的。
函數原型:
在理解原型之前有兩句很重要的話:
1、每一個函數對象都有一個prototype屬性,但是普通對象是沒有的;
prototype下麵又有個construetor,指向這個函數。
2、每個對象都有一個名為proto的內部屬性,指向它所對應的構造函數的原型對象,原型鏈基於proto;
prototype屬性
每個函數都有prototype屬性,預設指向一個Object空對象(稱為:原型對象)
1
2
3function Foo() {
}
console.log(Foo.prototype) //constructor __proto__
這裡為什麼要說是空對象,明明看到有constructor、__proto__
兩個屬性,其實是這個Object對象中沒有我們所需要的屬性,當然可以去向原型中添加我們需要屬性或者方法。
嘗試給原型對象添加屬性(一般都是方法)
1
|
Foo.prototype.method=function () {
|
此時在原型中可以看到method屬性已經添加到Foo()中去了。
現在我們通過創建實例去訪問我們剛纔添加的方法
1
|
var fun=new Foo()
|
可以看到構造函數跟原型對象是相互引用的關係。
這裡需要區分顯示原型和隱式原型
每個函數function都有一個prototype,即顯示原型(屬性)
每一個實例對象都有一個__proto__
稱為隱式原型(屬性)
我們繼續之前的構造函數:
1
|
var fun=new Foo()
|
可以看到對象的__proto__
屬性在創建對象時是自動添加的,預設值為構造函數的prototype屬性值。
constructor(構造函數)
在原型對象中有一個屬性constructor,當我們自定義構造函數之後,其原型對象只會預設取得constructor值,可以通過該屬性判斷出實例是由哪個構造函數創建的。
1
|
console.log(fun.prototype.constructor===Foo) //true
|
那麼構造函數的原型對象是由什麼來創建的呢?
我們去構造函數中尋找:
1
|
Foo.prototype.__proto__.constructor // ƒ Object() { [native code] }
|
這樣一來可以看到構造函數原型鏈的其他方法,原來是從Object 上繼承來的。
這裡的Object本來就存在,此時我們可以追溯到它的原型鏈。
原型鏈
原型鏈(本質上就隱式原型鏈,是用來查找對象的。)
在創建函數之前,已經就有了一個Object函數對象,js在載入引擎的時候首先會把這個內置的函數載入進來,然後在去執行我們的一些方法,訪問一個對象的屬性時,先從自身屬性中查找,找到返回,如果沒有,再沿著__proto__
這條鏈上查找,找到返回,如果最終沒找到,返回undefined。
註意事項:
-
函數的顯示原型指向的對象預設是Object實例對象(但是Object不滿足)
1
2
3console.log(Fn.prototype instanceof Object) //true
console.log(Object.prototype instanceof Object) //false
console.log(Function.prototype instanceof Object) //true -
所有函數都是Function的實例
1
console.log(Function.__proto__===Function.prototype) //true
-
Object的原型對象是原型鏈的盡頭
1
console.log(Object.prototype.__proto__) //null
-
(1)讀取對象的屬性值時,會自動到原型鏈中查找
(2)設置對象的屬性時,不會查找原型鏈,如果當前對象中沒有此屬性,直擊添加屬性並設置其值
(3)方法一定定義在原型中,屬性一般通過構造函數定義在對象本身上,1
2
3
4
5
6
7
8
9function Fn() {
}
Fn.prototype.a = 'xxx';
var fn1 = new Fn()
console.log(fn1.a, fn1)//xxx
var fn2 = new Fn()
fn2.a = 'yy'
console.log(fn2.a, fn2) //yy
一般情況下,我們會將屬性直接添加在函數中,
1
|
|
可以看實例對象的隱式原型等於構造函數的顯示原型,它們都構造函數都是指向的是Person,所以它們的proto都是相等的。