經過面試的挫折之後,繼續深入學習~~
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、小結
- 什麼是原型?
- 如何使用原型?
- 什麼是原型繼承? => 例項物件預設連線到原型中,可以繼承原型的方法和屬性,也可以自己給原型賦值
- 如何實現? => 混合式繼承