__proto__和prototype屬性:
1、__proto__屬性:
在JS裏,萬物皆對象(函數是對象、原型也是對象...)。對象都具有屬性__proto__,這個屬性會指向該對象的原型。
2、prototype屬性:
除此之外,函數(Function)也是對象,而且函數除了上面說的__proto__這個屬性外,還有額外的一個prototype屬性。函數的 prototype 屬性指向了一個對象,這個對象正是調用該構造函數而創建的實例的原型,也就是下面例子中的 person1 和 person2 的原型。
那什麼是原型呢?你可以這樣理解:每一個JavaScript對象(null除外)在創建的時候就會與之關聯另一個對象,這個對象就是我們所說的原型,每一個對象都會從原型"繼承"屬性。
原型鏈:
1、函數和原型關係:
我們先使用構造函數創建一個對象,Person 就是一個構造函數(注:首字母大寫只是約定俗成,不大寫照樣可以),我們使用 new 創建了兩個實例對象 person1和persion2。
function Person() { } // prototype是函數纔會有的屬性 Person.prototype.name = 'Kevin'; var person1 = new Person(); var person2 = new Person(); console.log(person1.name) // Kevin console.log(person2.name) // Kevin
讓我們用一張圖表示構造函數和實例原型之間的關係:
在這張圖中我們用 Object.prototype 表示實例原型。(構造)函數有一個prototype屬性,指向了實例原型。
2、實例和原型關係:
那麼我們該怎麼表示實例與實例原型,也就是 person 和 Person.prototype 之間的關係呢?很自然,我們知道沒有對象都有__proto__屬性,而且他指向的就是對象的原型。
function Person() { } var person = new Person(); console.log(person.__proto__ === Person.prototype); // true
3、構造函數:
既然實例對象和構造函數都可以指向原型,那麼原型是否有屬性指向構造函數或者實例呢?指向實例倒是沒有,因爲一個構造函數可以生成多個實例,但是原型指向構造函數倒是有的,如下代碼可以驗證
function Person() { } console.log(Person === Person.prototype.constructor); // true
講到這裏,我們知道了函數、對象實例和原型之間的關係了,他們是通過prototype和__proto__兩個屬性聯繫起來的。如下圖
4、原型鏈:
原型鏈就是依託__proto__和prototype連接起來的一個原型鏈條,我們先看個例子
function Person() { } // 原型屬性 Person.prototype.name = ‘Jiang’ var person1 = new Person() // 實例屬性 person1.name = ‘J’ console.log(person1.name) // J
上面代碼中在實例屬性和原型屬性都有一個名爲name的屬性,但是最後輸出來的是實例屬性上的值。
當我們讀取一個屬性的時候,如果在實例屬性上找到了,就讀取它,不會管原型屬性上是否還有相同的屬性,這其實就是屬性屏蔽,即當實例屬性和原型屬性擁有相同名字的時候,實例屬性會屏蔽原型屬性,記住只是屏蔽,不會修改,原型屬性那個值還在;但是如果在實例屬性上沒有找到的話,就會在實例的原型上去找,如果原型上還沒有,就繼續到原型的原型上去找,直到盡頭。
這個盡頭是啥?由於原型也是對象,所以也會有__proto__屬性,也就是原型的原型;最後就可以找到Object.prototype這個大boss,所有原型對象都是Object構造函數生成的(Object.prototype值爲null)。正是因爲所有的原型最終都會指向Object.prototype,所以對象的很多方法其實都是繼承於此,比如toString()、valueOf(),前面用到的hasOwnProperty,甚至是.constructor、proto
補充:一些常用方法:
1)檢查對象是否有該屬性:
function Person() { } var person1 = new Person() // 實例屬性 person1.name = ‘J’ person1.hasOwnProperty(‘name’) // true
注:hasOwnProperty屬性只有存在於實例中才會返回true
2)in則會遍歷所有屬性,不管是實例上的,還是原型上的:
function Person() { } Person.prototype.age = ‘100’ var person1 = new Person() person1.name = ‘J’ 'name' in person1 // true 'age' in person1 // true for (var prop in person1) { console.log(prop) // name age }
---------------------
作者:趕路人兒
來源:CSDN
原文:https://blog.csdn.net/liuxiao723846/article/details/81984357