引入從Object和Function開始
Object和Function都做爲JS的自帶函數,Object繼承本身,Funtion繼承本身,Object和Function互相是繼承對方,也就是說Object和Function都既是函數也是對象。函數
1 |
console.log(Function instanceof Object); // true |
Object 是 Function的實例,而Function是它本身的實例post
1 |
console.log(Function.prototype); // ƒ () { [native code] } |
普通對象和函數對象
JavaScript 中,萬物皆對象!但對象也是有區別的。分爲普通對象和函數對象,Object 、Function 是 JS 自帶的函數對象。下面舉例說明ui
1 |
var o1 = {}; |
在上面的例子中 o1 o2 o3 爲普通對象,f1 f2 f3 爲函數對象。怎麼區分,其實很簡單,凡是經過 new Function() 建立的對象都是函數對象,其餘的都是普通對象。f1,f2,歸根結底都是經過 new Function()的方式進行建立的。Function Object 也都是經過 New Function()建立的。this
函數原型:
在理解原型以前有兩句很重要的話:spa
一、每個函數對象都有一個prototype屬性,可是普通對象是沒有的;
prototype下面又有個construetor,指向這個函數。
二、每一個對象都有一個名爲proto的內部屬性,指向它所對應的構造函數的原型對象,原型鏈基於proto;prototype
prototype屬性
每一個函數都有prototype屬性,默認指向一個Object空對象(稱爲:原型對象)code
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() |
能夠看到構造函數跟原型對象是相互引用的關係。ip
這裏須要區分顯示原型和隱式原型
每一個函數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都是相等的。