JS原型和原型鏈

kari發表於2019-04-04

建構函式

JavaScript 通過建構函式生成新物件,因此建構函式可以視為物件的模板。例項物件的屬性和方法,可以定義在建構函式內部。

function Person (name, age) {
  this.name = name
  this.age = age
}

var person1 = new Person('kari', '18')

person1.name // 'kari'
person1.age // '18'
複製程式碼

上面程式碼中,Person 函式是一個建構函式,函式內部定義了 name 屬性和 age 屬性,所有例項物件(上例是 person1 )都會生成這兩個屬性,即這兩個屬性會定義在例項物件上面。

通過建構函式為例項物件定義屬性,雖然很方便,但是有一個缺點。同一個建構函式的多個例項之間,無法共享屬性,從而造成對系統資源的浪費。

function Person(name, age) {
  this.name = name
  this.age = age
  this.say = function () {
    console.log('hello')
  };
}

var person1 = new Person('老大', '20')
var person2 = new Person('老二', '18')

person1.say === person2.say
// false
複製程式碼

上面程式碼中,person1person2 是同一個建構函式的兩個例項,它們都具有 say 方法。由於 say 方法是生成在每個例項物件上面,所以兩個例項就生成了兩次。也就是說,每新建一個例項,就會新建一個 say 方法。這既沒有必要,又浪費系統資源,因為所有 say 方法都是同樣的行為,完全應該共享。

這個問題的解決方法,就是 JavaScript 的原型物件(prototype)。

JS原型

JavaScript 繼承機制的設計思想就是,原型物件的所有屬性和方法,都能被例項物件共享。也就是說,如果屬性和方法定義在原型上,那麼所有例項物件就能共享,不僅節省了記憶體,還體現了例項物件之間的聯絡。

function Person() {

}
var person1 = new Person()
var person2 = new Person()
person1.name = 'kari'

person1.name    // kari
person2.name    // undefined
複製程式碼
function Person() {

}
var person1 = new Person()
var person2 = new Person()
person1.__proto__.name = 'kari'

person1.name    // kari
person2.name    // kari
複製程式碼

__proto__ 和 prototype

__proto__ 是每個物件都有的一個屬性,而 prototype 是函式才會有的屬性。
__proto__ 指向的是當前物件原型物件,而 prototype 指向的是以當前函式作為建構函式構造出來的物件原型物件

通過下面這幅圖會更好的理解上面的兩句話:

JS原型和原型鏈
當構造了 Person 函式後,函式便會有一個屬性(prototype),指向原型物件

Person 函式被例項成 kari 後,kari 同樣也會有一個屬性(__proto__)指向原型物件

JS原型鏈

每個例項物件( object )都有一個私有屬性(稱之為 __proto__ )指向它的原型物件(prototype)。該原型物件也有一個自己的原型物件( __proto__ ) ,層層向上直到一個物件的原型物件為 null

根據定義,null 沒有原型,並作為這個原型鏈中的最後一個環節。

相關文章