【JS學習筆記】__proto__ vs. prototype
我是非本科系、正在學前端的新手,想用這裡記錄自己學到的東西。
【JS學習筆記】proto vs. prototype
我是非本科系、正在學前端的新手,想用這裡記錄自己學到的東西。
前陣子在學物件導向程式設計的時候,老師有教到 JS 的原型鏈 proto 跟 prototype。一開始在聽 proto 的概念時邏輯還算清晰,但接到 prototype 後思緒整個大混亂,這篇文章是想來整理一下上課教的以及我後來自己上網學的關於 JS 原型鏈。
proto 是每個物件都有的隱藏屬性。
prototype 是每個函式都有的屬性。(預設是一個物件)
proto
[[prototype]] (即 proto)
稍後講到 prototype 會提到 [[prototype]],所以這邊想先說明 [[prototype]] 跟 proto 是同個東西但為什麽要分兩個名字。
[[prototype]] 是 ECMAScript 規格書裡的內部欄位名稱,比較像是概念層面的東西,在 JS 程式碼裡是沒有的。
proto 則是我們實作在寫程式碼時會碰到的名稱。
const a = {}
console.log(a.name) //undefined
a 並沒有 name 這個屬性,所以會印出 undefined。
以初學者也就是我的角度會認為在 console.log(a.name) 時,電腦會去抓 a 然後看到它沒有 name 這個屬性後就回傳 undefined,但實際的操作是找 a 沒有 name,就會繼續往下找 a.proto 有沒有 name,如果沒有會再繼續往下找 a.proto.proto。
流程會是這樣:
a.name // 沒有,往下找
↓
a.__proto__.name // 沒有,繼續往下找
↓
a.__proto__.__proto__.name // 沒有,繼續往下找
↓
a.__proto__.__proto__.__proto__ // null,找不到 name 回傳 undefined
prototype
function A() {}
//函式也是物件所以也會有 __proto__
//而函式的 __proto__ 會指向 Function.prototype
const a = new A()
//new A() 時會建立一個物件,該物件的 __proto__ 會指向 A.prototype
A.__proto__ === Function.prototype // true
a.__proto__ === A.prototype // true
function A() {}
//每個函式都會有 prototype
A.prototype
//prototype會被預設為一個物件
prototype 能怎麼運用?
function A() {}
const greeting = {
sayHi: function(){
console.log("Hi!!!")
}}
A.prototype = greeting
const a = new A()
a.sayHi() // Hi!!!
a 本身沒有 sayHi ,上面有說過 new A() 時會建立一個物件,該物件的 proto 會指向 A.prototype ,而 A.prototype 被指定為 greeting ,這樣 new A() 時 sayHi 就可以被共用,所以這時 a.proto 會指向 greeting,a 就有了 sayHi。
大致流程是這樣:
a 本身沒有 sayHi
↓
會往 a.__proto__ 找
↓
a.__proto__ === A.prototype
↓
A.prototype === greeting
↓
找到 sayHi
上面是覆蓋 prototype 的方式,也可以直接往 prototype 加東西(擴充)
function A() {}
A.prototype.sayHi = function () {
console.log("Hi!!!")
}
const a = new A()
a.sayHi() // Hi!!!
覆蓋跟擴充兩者有什麼區別?
覆蓋和擴充最主要的差別是覆蓋會破壞函式本身的 constructor(建構函式)
前面有說到每個函式在被建立時都會有 prototype 的屬性(預設是個物件),而那個物件裡預設會有一個 constructor ,constructor 則會指向函式本身,雙向的關係。
function Dog(name) {
this.name = name
}
Dog.prototype.constructor === Dog // true
不建議用覆蓋的方式去寫,如果真的要覆蓋的話要再手動補回 constructor
Dog.prototype = {
constructor: Dog, // 補回來
bark: function() { console.log('汪!'); }
};

上面是 constructor 與 prototype 整體關係圖
function Dog(name) {
this.name = name;
}
Dog.prototype.bark = function() {
console.log(this.name + ' 汪汪!');
};
const rex = new Dog('Rex')
const lulu= new Dog('Lulu')
如果要寫物件導向程式設計時我選擇寫的方式會是
class 語法 > prototype 擴充 > prototype 覆蓋(補回constructor)
以上面的例子 class 語法的寫法會是:
class Dog {
constructor(name){
this.name = name
}
bark() {
console.log(this.name + ' 汪汪!')
}
} 메타데이터
- post_id
- a482d93edf6e
- slug
- js學習筆記-proto-vs-prototype-a482d93edf6e
- url
- https://medium.com/@lkimluu02/js%E5%AD%B8%E7%BF%92%E7%AD%86%E8%A8%98-proto-vs-prototype-a482d93edf6e
- canonical_url
- https://medium.com/@lkimluu02/js%E5%AD%B8%E7%BF%92%E7%AD%86%E8%A8%98-proto-vs-prototype-a482d93edf6e
- author_url
- https://medium.com/@lkimluu02
- status
- ok
- fetched_at
- 2026-08-02 13:24:08