繼承技巧
- 在
JavaScript
中繼承是指一個對象基於另一個對象 JavaScript
是利用prototype
來實現繼承以及來管理繼承。prototype
對象用途是所有實例共享的屬性。- 所有對象默認繼承來自
Object.prototype
構造函數竊取繼承
我利用竊取方式來實現繼承,也就是在子類構造函數來竊取父類構造函數。
call
/apply
來調用父類構造函數,需要把this
指向調用者。
function Person (name, age, role) {
this.name = name;
this.age = age;
this.role = role;
}
Person.prototype.sayName = function () {
console.log(`Hello, My name is ${this.name}`);
}
Person.prototype.role = function () {
console.log(`I'm a ${this.role}`);
}
function Student (name, age, role) {
Person.call(this, name, age, role)
}
// 使用 Object.create 會 return {} (如下)
// { constructor: Student } -> 對象.__proto__ 指向 Person.prototype
Student.prototype = Object.create(Person.prototype, {
constructor: {
configurable: true,
enumerable: true,
value: Student,
writable: true
}
})
const s = new Student('DecadeHew', 18, 'FrontEnd');
s.name // DecadeHew
s.sayName() // Hello, My name is DecadeHew
Object 繼承
- Object.create(prototype, defineProperty)
- 帶給我們最簡潔建立
prototypal inheritance
const person = {
type: 'Human',
walk: true
}
const me = Object.create(person, { name: { value: 'DecadeHew' } });
// me 繼承了 person 裡所有屬性,也可以說 me 享有 person 權利。
// me 也繼承了 Object.prototype
me.name // DecadeHew 自有屬性
me.type // Human
// 以下會列出 prototype 關係圖
me.__proto__ === person
me.__proto__.__proto__ === Object.prototype
me.__proto__.__proto__.__proto__ === null // 完畢
Prototype chain 繼承
- 每個函數都有 prototype 屬性。
- 每創建函數,就會同時創建它的
prototype
對象,prototype
對象也會自動有constructor
屬性。 prototype
對象也是一個對象,它也有自己的prototype
對象並繼承其屬性,這就是Prototype chain
。(依上面程式:me
對象繼承了Object.prototype
,享有Object
屬性和方法toString
,keys
…)
function Person (name, age, role) {
this.name = name;
this.age = age;
this.role = role;
}
Person.prototype.sayName = function () {
console.log(`Hello, My name is ${this.name}`);
}
Person.prototype.role = function () {
console.log(`I'm a ${this.role}`);
}
function Student (name, age, role) {
this.name = name;
this.age = age;
this.role = role;
}
// 為什麼我不寫 Student.prototype = Person.prototype;
// 因為 兩個構造函數的 prototype 都會指向同一個對象,
// 萬一我修改其中一個函數(Student)的 prototype,會影響另一個函數(Person)
Student.prototype = new Person();
Student.prototype.constructor = Student;
Student.prototype.role = function () {
console.log(`I'm a ${this.role}`);
}
const me = new Student('DecadeHew, 18)
me.name // DecadeHew
me.sayName() // Hello, My name is DecadeHew
// 以下會列出 prototype 關係圖
me.__proto__ === Student.prototype
me.__proto__.__proto__ === Person.prototype
me.__proto.__proto__.proto__ === Object.prototype
me.__proto.__proto__.proto__.__proto__ === null // 完畢
Object.prototype.__proto__ === null // 完畢
Student.prototype.__proto__ === Person.prototype
Person.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null // 完畢
// Function
Function.prototype.__proto__ === Object.prototype
Function.__proto__ === Function.prototype
Object.__proto__ === Function.prototype
Student.__proto__ === Function.prototype
Student.__proto__.__proto__ === Object.prototype
Student.__proto__.__proto__.__proto__ === null // 完畢
Object.prototype.__proto__ === null // 完畢