Day.21 「物件也有繼承問題?」 —— JavaScript 繼承 與 原型鍊

我們每新增一個函式,瀏覽器都會向函式內新增一個屬性叫 prototype
function Person() {};
console.log(Person.prototype)
原型鍊
如果是普通函式的直接調用,prototype 不會有任何作用
當是以構造函式的方式調用,他所新增的物件會有一個隱藏的屬性,指向該構造函式的原型物件。
雖然 prototype 是隱藏屬性,但我們可以透過 __proto__ 來查看該屬性
function Person() {};
const person = new Person()
console.log(person.__proto__)

也能發現 prototype 與 __proto__ 是一樣的
function Person() {};
const person = new Person()
console.log(Person.prototype === person.__proto__) // true繼承
依照之前物件傳址的特性,可以了解到物件中,共用的內容,可以設置到 prototype 中,新增的屬性就會繼承原型物件
function Person() {};
Person.prototype.a = '我是原型物件 a' // 添加原型物件屬性 a
const person = new Person()
console.log(person.a) // "我是原型物件 a"
可以發現如果物件內沒有 a 屬性,它就會往原型物件中尋找 a 屬性,如果找到就會使用。
function Person() {};
Person.prototype.a = '我是原型物件 a' // 添加原型物件屬性 a
const person = new Person()
person.a = '我是 person 中的 a'
console.log(person.a) // "我是 person 中的 a"
優化之前的 sayName
看到這裡是不是又發現可以更好優化自訂物件的方法了!
function Person(name, gender) {
this.name = name,
this.gender = gender
}
Person.prototype.sayName = function () {
console.log(`大家好!我是${this.name}`)
}
const person = new Person('毛毛', '男')
person.sayName() // "大家好!我是毛毛"就往原型物件尋找 sayName 方法,同時也不會汙染到我們的全局作用域!
檢查物件屬性
有時候,我們會需要檢查物件內有沒有該屬性,可以使用 in 語法來檢查:"屬性名" in 物件名,需注意屬性名要用引號包起來。
function Person(name, gender) {
this.name = name,
this.gender = gender
}
Person.prototype.sayName = function () {
console.log(`大家好!我是${this.name}`)
}
const person = new Person('毛毛', '男')
console.log('name' in person) // true
console.log('sayName' in person) // true但會發現,會連原型物件的屬性也判定為 true,
這時如果我們要更確實的判斷是不是該物件內的屬性,可以使用 hasOwnProperty() 語法來檢查
function Person(name, gender) {
this.name = name,
this.gender = gender
}
Person.prototype.sayName = function () {
console.log(`大家好!我是${this.name}`)
}
const person = new Person('毛毛', '男')
console.log(Object.hasOwn(person, 'name')) // true
console.log(Object.hasOwn(person, 'sayName')) // false這些「方法」都哪來的
沒錯!聰明的你應該已經更瞭解繼承與原型鍊,而我們常用的方法,其實都是在原型物件裡面!
function Person() {}
const person = new Person()
console.log('hasOwnProperty' in person) // true
console.log(Object.hasOwn(person, 'hasOwnProperty')) // false這時嘗試使用 __proto__ 找出原型
function Person() {}
const person = new Person()
console.log(Object.hasOwn(person.__proto__, 'hasOwnProperty')) // false原型物件中還有原型物件
你會發現,奇怪!怎麼還是 false,那是因為,原型物件也是物件,原型物件中還有原型物件!
當然!這不是無限套娃~會一路找到原型物件為 null 的值,代表該物件沒有原型物件了,而這個物件就是 Object 物件的原型!

function Person() {}
const person = new Person()
console.log(person.__proto__.__proto__) // Object
console.log(person.__proto__.__proto__.__proto__) // null
console.log(Object.hasOwn(person.__proto__.__proto__, 'hasOwnProperty')) // true總結
已經把我們的物件精隨學習的差不多了~也認識 JavaScript 中,我們常用的方法都藏在物件的隱藏屬性之中!
Related Posts
Day.30 「什麼!? Promise 的語法糖?」 —— ES8 Async & Await
ES8 新增了 async 與 await 兩個語法,這兩個語法也是為了更方便解決非同步的語法,可以說是 Promise then 的語法糖。
Day.29 「Class 語法糖~」 —— ES6 Class 構造函式
ES6 新增了更接近傳統語言寫法的 Class 這個概念,基本上可以當作是一個**語法糖**,絕大部分的功能在 ES5 都可以做到,但 Class 可以讓構造函式的寫法更加清新!
Day.28 「Promise 初體驗~」 —— ES6 Promise
我們前面已經學習了回調函式(Callback Function)與構造函式(Constrcutor),而 Promise 是 ES6 新增用來解決非同步回調地域的新語法,同時也是一個構造函式!
Johnson Mao
A passionate software engineer and blogger sharing thoughts on technology, AI, and development.