【JavaScript高級】原型與原型鏈

原型與原型鏈一直是JavaScript的重難點,掌握這部份內容將會使咱們的工做更加的高效,並且這也是面試官必問的內容。javascript

首先,咱們要明確的是,在 ES6 以前,咱們建立一個實例並非經過類(class),而是直接使用構造函數來實現的。java

1、構造函數

經過 new 函數名 來實例化對象的函數叫構造函數。任何的函數均可以做爲構造函數存在。構造函數首字母通常大寫。面試

那麼,咱們使用構造函數來建立一個對象。瀏覽器

function Person(name , age , sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
}
var person = new Person("Tony" , 18 , "男");
console.log(person.name);  // Tony
複製代碼

上面這段代碼就是建立一個了Person 的構造函數,在Person 構造函數中,爲每個對象都添加了三個屬性(name,age,sex),也就是說構造函數每執行一次就會建立一個新的Person對象。markdown

構造函數簡單複習一下,下面步入正題。函數

2、原型

prototype

在JS中,每當定義一個函數時候,都會默認自帶一個prototype屬性,這個屬性指向的是該構造函數建立的實例的原型,而且這個屬性是一個對象數據類型的值。ui

原型:每個JS對象(null除外)在建立的時候就會與之關聯另外一個對象,這個對象就是咱們所說的原型,每個對象都會從原型"繼承"屬性。this

舉個原型的Demo:spa

function Person() { }
Person.prototype.name = 'Tony';  // 注意:prototype是函數纔會有的屬性
var person1 = new Person();
var person2 = new Person();
console.log(person1.name);  // Tony
console.log(person2.name);  // Tony
複製代碼

構造函數和實例原型之間的關係: 構造函數和實例原型之間的關係: 在這裏 Person.prototype 表示實例原型。原型對象就至關於一個公共的區域,全部同一個類的實例均可以訪問到這個原型對象,咱們能夠將對象中共有的內容,統一設置到原型對象中。prototype

3、原型鏈

上面,咱們說明了實例和實例原型,那麼咱們該怎麼表示這二者之間的關係呢?這時候咱們就要說到下面兩個屬性了

__proto__

這是每個JS 對象(除了 null )都具備的一個屬性,叫__proto__,這個屬性會指向該對象的原型。

person.__proto__ === Person.prototype   // true
複製代碼

__proto__ 絕大部分瀏覽器都支持這個非標準的方法訪問原型,然而它並不存在於 Person.prototype 中,實際上,它是來自於 Object.prototype ,與其說是一個屬性,不如說是一個 getter/setter,當使用 obj.__proto__ 時,能夠理解成返回了 Object.getPrototypeOf(obj)

constructor

每一個原型都有一個 constructor 屬性指向關聯的構造函數。

Person === Person.prototype.constructor  // true
複製代碼

當獲取 person.constructor 時,其實 person 中並無 constructor 屬性,當不能讀取到constructor 屬性時,會從 person 的原型也就是 Person.prototype 中讀取,正好原型中有該屬性,因此:

person.constructor === Person.prototype.constructor
複製代碼

實例原型與構造函數的關係圖: 實例原型與構造函數的關係圖 原型鏈:在JS中,萬物皆對象,對象和對象之間也是有關係得,並非孤立存在的。對象之間的繼承關係,在JS 中是經過prototype對象指向父類對象,直到指向Object對象爲止,這樣就造成了一個原型指向的鏈條,專業術語稱之爲原型鏈。

實例和原型

當咱們讀取實例的一個屬性或方法時,它會先在對象自身中尋找,若是有則直接使用,若是沒有則會去原型對象中尋找,若是找到則直接使用。若是沒有則去原型的原型中尋找,一直找到最頂層Object爲止,Object對象的原型沒有原型(Object是JS中全部對象數據類型的基類(最頂層的類)在Object.prototype上沒有__proto__這個屬性),若是在Object原型中依然沒有找到,則返回undefined

function Person() {}
Person.prototype.name = 'Tony';
var person = new Person();

// 當咱們給實例對象person添加了name屬性,打印 person.name 時,結果爲name的值Ken。
person.name = 'Ken';
console.log(person.name) // Ken

// 當咱們刪除了person的name屬性時,再次讀取person.name,從person 對象中找不到name屬性就會從person的原型也就是person.__proto__和Person.prototype中查找name屬性,由於以前咱們給他添加了,因此找到了 name屬性爲 Tony。
delete person.name;
console.log(person.name) // Tony
複製代碼

咱們能夠使用對象的hasOwnProperty()來檢查對象自身中是否含有該屬性,若是自身屬性存在,則返回 true,不然爲false;使用in檢查對象中是否含有某個屬性時,若是對象中沒有可是原型中有,則會返回true,若是都沒有則返回false

function Person() {
    this.name = 'Tony'
}

Person.prototype.age = 18;

var person = new Person();

console.log(person.hasOwnProperty('name')); // true
console.log(person.hasOwnProperty('age'));  // false

console.log('name' in person);  // true
console.log('age' in person);   // true
console.log('a' in person);     // false
複製代碼

最後,相互關聯的原型組成的鏈狀結構就是原型鏈,也就是藍色的這條線: 在這裏插入圖片描述


用心讀完上面的總結,應該會對 JS 的原型與原型鏈有了一個深層次的認識吧,其實這部分仍是須要細心琢磨的,畢竟是比較底層的原理。

相關文章
相關標籤/搜索