javascript
JS中的prototype、__proto__与constructor,原型和原型链
理解原型的幾個關鍵點:
1、所有的引用類型(數組、函數、對象)可以自由擴展屬性(除null以外);
2、所有的引用類型(對象)都有一個’_ _ proto_ _'屬性(也叫隱式原型,它是一個普通的對象),指向原型對象;
3、所有的函數都有一個’prototype’屬性(這也叫顯式原型,它也是一個普通的對象,該對象就是函數的原型對象,對象中包含所有實例對象可以共享的屬性和方法)。’prototype’屬性是函數獨有的,任何函數在創建的時候,其實會默認同時創建該函數的prototype對象;
4、所有引用類型,它的’_ _ proto_ _'屬性指向它的構造函數的’prototype’屬性(所以? 函數._ _ proto_ _ ===function.prototype);
5、當試圖得到一個對象的屬性時,如果這個對象本身不存在這個屬性,那么就會去它的’_ _ proto_ _'屬性(也就是它的構造函數的’prototype’屬性)中去尋找。
6、constructor屬性也是對象才擁有的,指向該對象的構造函數。函數創建的對象.__proto__ === 該函數.prototype,該函數.prototype.constructor===該函數本身,故通過函數創建的對象即使自己沒有constructor屬性,它也能通過__proto__找到對應的constructor,所以任何對象最終都可以找到其構造函數(null如果當成對象的話,將null除外)
?
?
原型:
先來看一個原型的例子。
//這是一個構造函數function Foo(name,age){this.name=name;this.age=age;}/*根據要點3,所有的函數都有一個prototype屬性,這個屬性是一個對象再根據要點1,所有的對象可以自由擴展屬性于是就有了以下寫法*/Foo.prototype={// prototype對象里面又有其他的屬性showName:function(){console.log("I'm "+this.name);//this是什么要看執行的時候誰調用了這個函數},showAge:function(){console.log("And I'm "+this.age);//this是什么要看執行的時候誰調用了這個函數}}var fn=new Foo('小明',19)/*當試圖得到一個對象的屬性時,如果這個對象本身不存在這個屬性,那么就會去它構造函數的'prototype'屬性中去找*/fn.showName(); //I'm 小明fn.showAge(); //And I'm 19這就是原型,很好理解。那為什么要使用原型呢?
試想如果我們要通過Foo()來創建很多很多個對象,如果我們是這樣子寫的話:
function Foo(name,age){this.name=name;this.age=age;this.showName=function(){console.log("I'm "+this.name);}this.showAge=function(){console.log("And I'm "+this.age);}}那么我們創建出來的每一個對象,里面都有showName和showAge方法,這樣就會占用很多的資源。
而通過原型來實現的話,只需要在構造函數里面給屬性賦值,而把方法寫在Foo.prototype屬性(這個屬性是唯一的)里面。這樣每個對象都可以使用prototype屬性里面的showName、showAge方法,并且節省了不少的資源。
?
?
原型鏈
理解了原型,那么原型鏈就更好理解了。
#####下面這段話可以幫助理解原型鏈
根據要點5,當試圖得到一個對象的屬性時,如果這個對象本身不存在這個屬性,那么就會去它構造函數的’prototype’屬性中去尋找。那又因為’prototype’屬性是一個對象,所以它也有一個’_ _ proto_ _'屬性。
?
是不是覺得有點奇怪?我們來分析一下。
?
首先,fn的構造函數是Foo()。所以:
fn._ _ proto _ _=== Foo.prototype
又因為Foo.prototype是一個普通的對象,它的構造函數是Object,所以:
Foo.prototype._ _ proto _ _=== Object.prototype
通過上面的代碼,我們知道這個toString()方法是在Object.prototype里面的,當調用這個對象的本身并不存在的方法時,它會一層一層地往上去找,一直到null為止。
所以當fn調用toString()時,JS發現fn中沒有這個方法,于是它就去Foo.prototype中去找,發現還是沒有這個方法,然后就去Object.prototype中去找,找到了,就調用Object.prototype中的toString()方法。
__proto__屬性的作用就是當訪問一個對象的屬性時,如果該對象內部不存在這個屬性,那么就會去它的__proto__屬性所指向的那個對象(父對象)里找,一直找,直到__proto__屬性的終點null,再往上找就相當于在null上取值,會報錯。通過__proto__屬性將對象連接起來的這條鏈路即我們所謂的原型鏈。
?
另外,在使用原型的時候,一般推薦將需要擴展的方法寫在構造函數的prototype屬性中,避免寫在_ _ proto _ _屬性里面。
?
總結:
- 當所有的實例對象都需要共享屬性和方法時,通過原型來實現就是將屬性方法放在實例對象的構造函數的prototype屬性中(該屬性值就是原型對象,包含共享屬性和方法);
- ??訪問一個對象的屬性時,先在基本屬性中查找,如果沒有,再沿著__proto__這條鏈向上找,這就是原型鏈。
- 根據原型鏈可以確定繼承關系。由于所有的對象的原型鏈都會找到Object.prototype,因此所有的對象都會有Object.prototype的方法。這就是所謂的“繼承”。
- 對象引用類型通過instanceof來判斷。
?
?
版權聲明:文章內容主要綜合來自鏈接處,
https://blog.csdn.net/qq_36996271/article/details/82527256
https://blog.csdn.net/cc18868876837/article/details/81211729
總結
以上是生活随笔為你收集整理的JS中的prototype、__proto__与constructor,原型和原型链的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C指针原理(19)-C指针基础
- 下一篇: C指针原理(20)-C指针基础