JavaScript物件導向 ~ 原型和繼承(1)

默默發表於2019-02-16

經過面試的挫折之後,繼續深入學習~~

1、原型概念的提出

傳統的建構函式物件包含方法時,在建構函式建立時,就會將所有內容重新建立一次,導致資料的重複,程式碼的冗餘,如下所示:

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.sayHello = function () {
    console.log("Hello");
  }
}
var p1 = new Person();
var p2 = new Person();
p1.sayHello === p2.sayHello // 結果為false,因為p1,和p2的sayHello雖結構一樣,但卻是兩個不同的物件

改良1:將方法提取到外面

function sayHello(){
  console.log("Hello");
}
function Person(name, age) {
  this.name = name;
  this.age = age;
  this.sayHello = sayHello;
}
var p1 = new Person();
var p2 = new Person();
p1.sayHello === p2.sayHello // 結果為true,但當程式碼量不斷增加,自定義的函式越來越多時,可能會和框架中的函式發生命名衝突,也不利於程式碼的維護

改良2:將方法放到建構函式中,且避免命名衝突,原型概念出現

function Person(name, age) {
  this.name = name;
  this.age = age;
}
Person.prototype.sayHello = function (){
   console.log("Hello");
}
var p1 = new Person();
var p2 = new Person();
p1.sayHello === p2.sayHello // 結果為true

建構函式一旦被建立,就會有一個原型屬性,也是個物件,可以往裡面新增成員,每個由建構函式建立出來的物件都會預設連線到原型屬性上去。

當js引擎查詢物件屬性時,會先查詢物件上是否具有該屬性,如果沒有,就會去原型屬性上去查詢。

所以,什麼是原型?原型是能夠實現繼承的,當建構函式被定義的時候,原型也就被建立出來,它可以儲存屬性和方法,既是一個屬性也是一個物件。當建構函式建立的例項物件需要訪問某個方法或屬性,而這個物件又沒有該方法或屬性的時候,它會去原型上面去查詢。也就是例項物件訪問原型物件的屬性或呼叫原型物件的方法,說的通俗一點也就是把別的物件的方法或屬性拿過來自己用,就是繼承,所以我們也可以說物件繼承自其原型。

引入:屬性查詢機制:物件在訪問屬性或方法時,首先在當前物件查詢,如果該物件有該屬性或方法,則停止查詢,如果沒有,則去原型中查詢,如果原型沒有,則去原型的原型中查詢,直到原型的頂部,如果還是沒有,則返回undefined(屬性)或 xxx is not a function(方法)

2、一些相關概念

① 物件導向的相關概念

  • 類class:在js中就是建構函式
  • 例項(instance)與物件(object)
    例項是指某個建構函式建立出來的物件,我們稱之為xxx建構函式的例項;
  • 鍵值對與屬性和方法
    在js中,鍵值對的集合稱之為物件
    如果資料是值,該鍵值對為屬性prototype
    如果資料是函式,該鍵值對為方法method
  • 父類與子類
    js中沒有class的概念,由C++引申過來,父類又稱基類,子類又稱派生類
    js中稱為父物件、子物件

② 原型的相關概念

  • prototype針對建構函式,稱為“原型屬性”
  • prototype針對建構函式建立出來的物件,稱為“原型物件”
  • 原型屬性與原型物件的關係:
    !!建構函式的原型屬性和建構函式建立出來的物件的原型物件,是一個東西
    !!建構函式的原型屬性所指向的物件,與建構函式建立出來的物件(例項物件),這是兩個不同的物件(快繞暈了)

3、物件繼承自其原型

建構函式建立出來的物件(例項物件)繼承建構函式的原型屬性和原型物件

4、原型的使用

  • 利用物件的動態特性:在原來的物件上新增成員
    建構函式.prototype.xxx = ccc;
  • 直接替換:重新建立一個物件
    建構函式.prototype = {};

5、__proto__

通過 proto 允許例項物件直接訪問原型,通常用於在除錯中檢視原型的成員(例項物件不允許修改原型)

6、原型的結構

有一個預設屬性:constructor => 構造器,表示該原型是與什麼建構函式聯絡起來的
∴ 建構函式通過 prototype 的屬性訪問原型,原型可以通過 constructor 訪問建構函式

7、繼承

  • 簡單繼承:將別的物件的方法或屬性直接拿過來,加到自己身上,於是我就有了該方法或屬性。=> 簡單粗暴,層次清晰
  • 利用原型繼承:不需要新增成員,只要原型具有,我便有了。=> 提高複用性
  • 混合式繼承:將方法或屬性利用混入的方法,加到建構函式原型中,例項物件即有了指定的方法或屬性。

8、靜態成員和例項成員的概念

該概念由其他物件導向的語言引入。

  • 靜態成員表示的是靜態方法和靜態屬性,由建構函式提供。
  • 例項成員表示的是例項方法和例項屬性,由建構函式建立的物件,也就是例項物件提供。

9、小結

  • 什麼是原型?
  • 如何使用原型?
  • 什麼是原型繼承? => 例項物件預設連線到原型中,可以繼承原型的方法和屬性,也可以自己給原型賦值
  • 如何實現? => 混合式繼承

相關文章