[JS奇怪的世界]No.47 瞭解原型

前言

JavaScript 用了原型繼承,所以代表有個叫作原型(prototype)的概念。

瞭解原型

首先我們知道物件可以有屬性和方法,然後我們可以使用點運算子取得屬性或方法,JavaScript 中所有物件、函數,都有原型屬性,而這個屬性會參考到另一個屬性通常被稱為 proto。

假設今天我們有一個 obj 的物件,底下有一個叫 prop1,所以我們可以透過 obj.prop1 來取得。

JavaScript 中所有物件、函數,都有原型屬性。

而這個屬性會參考到另一個物件,稱之為 proto,而 proto 也可以有屬性,例如 prop2,所以當我們要取用 prop2時就可以這樣寫 obj.prop2

而我們使用點運算子去取用 obj 中的 prop2 時,會找不到,所以他會往原型裡面找。

那原型物件也可以指向到另一個物件。

每個物件都可以有自己的原型,當這個 proto 裡面有一個 prop3,我們就可以用 obj.prop3 取得。

而這過程就像一個鏈子,所以又稱為原型鏈 (prototype chain),但是不要把他跟範圍鏈搞混了,雖然很相似,可是範圍鏈是尋找可以取用的變數,但原型鏈是尋找屬性及方法。

而一般來講這 proto 是隱藏起來的,所以我們才不用這樣撰寫 obj.proto.proto.prop3,只需要 obj.prop3 就好。

但是 JavaScript 中有一個很有趣的狀況,當若有第二個 obj 時,他可以指向同一個原型。

所以當我們呼叫 obj2.prop2,他一樣會回傳相同位子。

而以上這些就是原型及原型鏈個概念,只需要想簡單一點只是有一個特別的參考到我們的物件而已,那接下來我們直接來看點範例。

1
2
3
4
5
6
7
8
9
10
11
12
var person = {
firstname: 'Default',
lastname: 'Default',
getFullName: function() {
return this.firstname + ' ' + this.lastname;
}
}

var john = {
firstname: 'John',
lastname: 'Doe',
}

這邊我們有兩個物件,接下來我們要將 john 設定成原型,但以下範例千萬不要使用於現實中,這只是為了簡單理解觀念而已。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var person = {
firstname: 'Default',
lastname: 'Default',
getFullName: function() {
return this.firstname + ' ' + this.lastname;
}
}

var john = {
firstname: 'John',
lastname: 'Doe',
}
// 千萬不要使用這種方式在真正的專案開發上,這只是為了理解原型而已。
john.__proto__ = person;
console.log(john.getFullName());

為什麼不是抓到 Default?因為原型鏈的原因導致,所以點運算子會在 john 裡面找到 firstname,所以就會停下來不會再找了,接下來在加一點物件上去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var person = {
firstname: 'Default',
lastname: 'Default',
getFullName: function() {
return this.firstname + ' ' + this.lastname;
}
}

var john = {
firstname: 'John',
lastname: 'Doe',
}
// 千萬不要使用這種方式在真正的專案開發上,這只是為了理解原型而已。
john.__proto__ = person;
console.log(john.getFullName());

var jane = {
firstname: 'jane',
}

// 千萬不要使用這種方式在真正的專案開發上,這只是為了理解原型而已。
jane.__proto__ = person;
console.log(jane.lastname);
console.log(jane.getFullName());

相信看到這邊已經越來越清楚怎麼跑了。

圖源

JavaScript 全攻略:克服 JS 奇怪的部分

0%