[[Prototype]] 是在 JavaScript 中物件的特殊隱藏屬性,這個屬性對應到的就是該物件的原型,但因[[Prototype]] 為內部屬性無法直接訪問到,因此可以透過__proto__、Object.getPrototypeOf()的訪問原型
//Person 是一個建構函式
function Person(name) {
this.name = name;
console.log(this);
}
//透過 Person 建構函式,創建了一個 ming 物件
const ming = new Person("小明");
//ming物件可以透過 __proto__ 方法訪問到它的原型
console.log(ming.__proto__);
//建構函式透過prototype 方法與實例指向同個原型
console.log(Person.prototype);
//答案true,建構函式透過prototype 方法與實例指向同個原型
console.log(Person.prototype === ming.__proto__);
console.log(Object.getPrototypeOf( Person ) === Function.prototype); // true
//答案true,或是使用 Object.getPrototypeOf(ming)
console.log(Person.prototype === Object.getPrototypeOf(ming));
console.log(Person.__proto__ === Function.prototype);
//答案false
console.log(ming.__proto__ === Function.prototype );
console.log(Person.prototype === Function.prototype);
Person的prototype屬性不等於Function的prototype屬性,在這Person.prototype所指向的是實例的原型
//false
console.log(Person.prototype === Function.prototype);
但如果將Peson屬性改為__proto__,此時結果為true,由此可知Person函式繼承自Function原型,因此它的__proto__才會指向Function.prototype
//true
console.log(Person.__proto__ === Function.prototype);
當你在 JavaScript 中使用一個物件來存取屬性或方法時,如果這個物件本身沒有該屬性,它就會沿著一條「路徑」往上找,這條路徑就是原型鏈
一句話解釋原型鏈:
物件訪問 [[Prototype]](也就是__proto__)往上一層查找屬性或方法的機制。
//true
//原型鏈的終點會是null
console.log(ming.__proto__.__proto__.__proto__ === null);
ming 本身並沒有 run 方法這個屬性,但它可以透過原型鏈(__proto__指向 Person.prototype)繼承來使用這個方法,當我們在 Person.prototype 上定義了 run 方法後,ming 雖然沒有自己的 run,但仍然可以呼叫,這就是透過原型繼承來取得方法的實例
// Person 是一個構造函式
function Person(name) {
this.name = name;
}
// 透過 Person 建構函式,創建了一個 ming 對象
const ming = new Person("小明");
// 在 Person.prototype 上定義 run 方法
Person.prototype.run = function () {
console.log(`${this.name}可以跑`);
};
// 查看 Person 的共享原型
console.dir(Person.prototype);
// ming 可使用這個方法
ming.run();
Dog.prototype(用來給實例繼承的原型)是個物件,它的原型是 Object.prototype
// Dog.prototype 本身也是一個物件,所以它的原型是 Object.prototype
console.log(typeof Dog.prototype); // 'object'
console.log(Dog.prototype.__proto__ === Object.prototype); // true
Dog(建構函式)的原型是 Function.prototype
console.log(Dog.__proto__ === Function.prototype); // true
函式建構子
function Person(name) {
this.name = name;
console.log(this);
}
const ming = new Person("小明");
console.log(ming);
Dog 函式是一份藍圖或設計圖
👉 就像建築的設計圖,定義了每個實體該有哪些屬性(如:name、color)。
new Dog(...) 是根據這份藍圖打造出來的具體東西
👉 每次使用 new
都會產生一個新的「物件實體」,就像依照設計圖蓋出一棟新房子或養出一隻新狗。
使用 new Dog(...) 建立的物件會繼承 Dog.prototype 上的所有方法
👉 這些方法就像是工具箱裡的工具,每個物件都可以共用,避免每次都重複定義。
Dog.prototype 就像是藍圖附帶的共用工具箱
👉 設計圖不僅規範結構,也提供了一套通用的操作工具(如:run()
方法)。
👉 Dog.prototype 本身就是一個物件,所以它的 proto 指向 Object.prototype
this 代表目前正在建構的那個實體(這一棟房子/這一隻狗)
👉 當你在 Dog
函式裡寫 this.name = name;
,意思就是:把 name
這個屬性裝到「這個實體」身上。
function Dog(name, color) {
this.name = name;
this.color = color;
}
Dog.prototype.run = function(){
return this.name + '可以跑';
};
const 小白 = new Dog("小白", "白色");
const 小黃 = new Dog("小黃", "黃色");
console.log(小白.run());
console.log(Dog);
class建構子
class建構子也可達成像上述一樣的效果
class Dog {
constructor(name, color) {
this.name = name;
this.color = color;
}
run() {
console.log(`${this.name}可以跑`);
}
}
const 小白 = new Dog("小白", "白色");
const 小黃 = new Dog("小黃", "黃色");
小白.run();
console.log(Dog);
類別繼承(class & extends)
class Animal {
constructor(type) {
this.type = type || "都是人"; // 若沒傳 type,預設為 "都是人"
}
walk() {
console.log(`${this.name}可以走`);
}
}
class Dog {
constructor(name, color) {
this.name = name;
this.color = color;
}
run() {
console.log(`${this.name}可以跑`);
}
}
class Cat extends Animal {
constructor(name, color) {
super("貓"); // 呼叫 Animal 的 constructor 並傳入 type = "貓"
this.name = name;
this.color = color;
}
meow() {
console.log(`${this.name}喵喵叫`);
}
}
Dog 是獨立的類別,沒有繼承 Animal
class Dog {
constructor(name, color) {
this.name = name;
this.color = color;
}
run() {
console.log(`${this.name}可以跑`);
}
}
Cat 類別繼承 Animal
class Cat extends Animal {
constructor(name, color) {
super("貓"); // 呼叫 Animal 的 constructor 並傳入 type = "貓"
this.name = name;
this.color = color;
}
meow() {
console.log(`${this.name}喵喵叫`);
}
}
執行結果
const 小白 = new Dog("小白", "白色");
小白.run(); // 小白可以跑
const 小喵 = new Cat("小喵", "黃色");
小喵.meow(); // 小喵喵喵叫
小喵.walk(); // 小喵可以走
console.log(小喵); // 印出 Cat 實例,含 name, color, type
參考資料
(https://www.explainthis.io/zh-hant/swe/most-common-js-prototype-questions)
(https://javascript.alphacamp.co/prototype-prototype-chain.html)