1. 程式人生 > >原型與原型鏈詳解

原型與原型鏈詳解

前言

與大部分面嚮物件語言不同,ES6之前中並沒有引入類(class)的概念,JavaScript並非通過類而是直接通過建構函式來建立例項。在介紹原型和原型鏈之前,我們有必要先複習一下建構函式的知識。

一、建構函式

建構函式模式的目的就是為了建立一個自定義類,並且建立這個類的例項。建構函式模式中擁有了類和例項的概念,並且例項和例項之間是相互獨立的,即例項識別。

建構函式就是一個普通的函式,建立方式和普通函式沒有區別,不同的是建構函式習慣上首字母大寫。另外就是呼叫方式的不同,普通函式是直接呼叫,而建構函式需要使用new關鍵字來呼叫

	function Person(name, age, gender) {
		this.name = name
		this.age = age
		this.gender = gender
		this.sayName = function () {
			alert(this.name);
		}
	}
	var per = new Person("孫悟空", 18, "男");
	function Dog(name, age, gender) {
		this.name = name
		this.age = age
		this.gender = gender
	}
	var dog = new Dog("旺財", 4, "雄")
	console.log(per);//當我們直接在頁面中列印一個物件時,事件上是輸出的物件的toString()方法的返回值
	console.log(dog);
複製程式碼

 

 

 

每建立一個Person建構函式,在Person建構函式中,為每一個物件都添加了一個sayName方法,也就是說建構函式每執行一次就會建立一個新的sayName方法。這樣就導致了建構函式執行一次就會建立一個新的方法,執行10000次就會建立10000個新的方法,而10000個方法都是一摸一樣的,為什麼不把這個方法單獨放到一個地方,並讓所有的例項都可以訪問到呢?這就需要原型(prototype)

二、原型

在JavaScript中,每當定義一個函式資料型別(普通函式、類)時候,都會天生自帶一個prototype屬性,這個屬性指向函式的原型物件,並且這個屬性是一個物件資料型別的值。

讓我們用一張圖表示建構函式和例項原型之間的關係:

 

 

原型物件就相當於一個公共的區域,所有同一個類的例項都可以訪問到這個原型物件,我們可以將物件中共有的內容,統一設定到原型物件中。

 

三、原型鏈

1.__proto__constructor

每一個物件資料型別(普通的物件、例項、prototype......)也天生自帶一個屬性__proto__,屬性值是當前例項所屬類的原型(prototype)。原型物件中有一個屬性constructor, 它指向函式物件。

    function Person() {}
    var person = new Person()
    console.log(person.__proto__ === Person.prototype)//true
    console.log(Person.prototype.constructor===Person)//true
    //順便學習一個ES5的方法,可以獲得物件的原型
    console.log(Object.getPrototypeOf(person) === Person.prototype) // true
複製程式碼

 

 

 

2.何為原型鏈

在JavaScript中萬物都是物件,物件和物件之間也有關係,並不是孤立存在的。物件之間的繼承關係,在JavaScript中是通過prototype物件指向父類物件,直到指向Object物件為止,這樣就形成了一個原型指向的鏈條,專業術語稱之為原型鏈

舉例說明:person → Person → Object ,普通人繼承人類,人類繼承物件類

當我們訪問物件的一個屬性或方法時,它會先在物件自身中尋找,如果有則直接使用,如果沒有則會去原型物件中尋找,如果找到則直接使用。如果沒有則去原型的原型中尋找,直到找到Object物件的原型,Object物件的原型沒有原型,如果在Object原型中依然沒有找到,則返回undefined。

我們可以使用物件的hasOwnProperty()來檢查物件自身中是否含有該屬性;使用in檢查物件中是否含有某個屬性時,如果物件中沒有但是原型中有,也會返回true

	function Person() {}
	Person.prototype.a = 123;
	Person.prototype.sayHello = function () {
	  alert("hello");
	};
	var person = new Person()
	console.log(person.a)//123
	console.log(person.hasOwnProperty('a'));//false
	console.log('a'in person)//true
複製程式碼

person例項中沒有a這個屬性,從 person 物件中找不到 a 屬性就會從 person 的原型也就是 person.__proto__ ,也就是 Person.prototype中查詢,很幸運地得到a的值為123。那假如 person.__proto__中也沒有該屬性,又該如何查詢?

當讀取例項的屬性時,如果找不到,就會查詢與物件關聯的原型中的屬性,如果還查不到,就去找原型的原型,一直找到最頂層Object為止。Object是JS中所有物件資料型別的基類(最頂層的類)在Object.prototype上沒有__proto__這個屬性。

console.log(Object.prototype.__proto__ === null) // true
複製程式碼

 

 

如果覺得文章對你有些許幫助,歡迎在我的GitHub部落格點贊和關注,感激不盡!

 

參考文章

最詳盡的 JS 原型與原型鏈終極詳解,沒有「可能是」。(一)

JavaScript深入之從原型到原型鏈


作者:浪裡行舟
連結:https://juejin.im/post/5bb7183bf265da0a9e5322b1
來源:掘金
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。