Constructor Function
在JS
裡所有事物都是對象,function
也是對象。
構造函數透過new
operator 可以創建新的對象Object
。如不使用 new
和一般函數沒有區別。
- 在
js
裡,new
是用來創建一個對象new
構造函數(參數) -> 實例對象
基本 new
實現 思路:
- 創建新的實例對象
- 實例對象proto 指向於 構造函數.prototype
- 構造函數裡 this 指向實例對象
- 返回實例對象
可以參考 ☞ 我寫了一個實現 new
Prototype 是什麼
JavaScript 基於 原型。
我們可以使用prototype
來添加屬性/方法給所有有關實例對象都能共享。
Prototype Rules
必須牢記在心這些規則是在了解
prototype chain
基礎上
- 每個函數都有
prototype
屬性- 每個對象內部屬性都有隱式
__proto__
- 每個實例的
__proto__
指向創建它的構造函數的prototype
- 每個函數是由
Function
所創建的。Function.prototype
===一般函數.__proto__
一般函數.prototype.__proto__
===Object.prototype
為何使用 Prototype 呢?
function Cat(name) {
this.lives = 9;
this.name = name;
this.sayName = function () {
console.log(`Meow! My name is ${this.name}`);
};
}
const c1 = new Cat('cat1');
const c2 = new Cat('cat2');
c2.sayName = 'haha';
c1.sayName() // Meow! My name is cat1
c2.sayName() // haha
根據以上程式來講解,我把 c2.sayName
屬性值原函數改成字串haha。當 c1.sayName
還是一樣是函數。因為 c1
和 c2
對象是不相等的,當然你改變某個對象的屬性是不會影響到另一個對象。如果你想要是這樣,其實是沒問題。
問題來了,我想要在我改某一個對象的屬性值時,另一個對象也需要立即得到反映。在這前提下,兩個對象必須是由 Cat構造函數所創建對象,如 c1
和 c2
。 再回來這個問題 sayName
屬性的變更,如何共享其他對象了。
就是把 sayName
屬性存在 prototype
對象裡,這樣一來可以節省空間也可以讓所有實例對象共享(享用) prototype
對象所保存的屬性和方法,只要 prototype
對象裡屬性修改,可以立即在所有實例得到反映。稍微講解為何使用 prototype
可以節省空間呢。可以想像下,透過 new
來創建多個對象,多個對象裡屬性是一樣,這樣會佔用內存。
當然我們可以分類哪個需要放在構造函數哪個需要放在 prototype
。
- 具體某個對象的特定屬性,通常放在構造函數裡。例如
name
,age
等等,因為每個對象name
,age
有所不同,僅僅只有特定屬於某個對象。 - 所有對象都可以共享屬性和方法,通常放在
prototype
對象裡。 例如sayName
等等,因為所有對象可以共同訪問當前sayName
的值,指是所有對象一個共同動作。
Prototype chain
Prototype chain
主要實現了繼承方法。- 每個
prototype
裡都有指向它自己prototype
,這叫做prototype chain
- 每個構造函數都有一個屬性
prototype
對象,那麼prototype
對象都包含一個__proto__
並指向創建它構造函數的prototype
(Object.prototype
)。 - 每個實例對象都有一個屬性
__proto__
對象指向prototype
對象(Object.prototype
)。
function fn() {}
fn.prototype.__proto__ === Object.prototype // true
const obj = {}
obj.__proto__ === Object.prototype // true
Prototype & Prototype Chain
- 為了節省空間,我們會把
methods
添加到prototype
裡。 - 全部對象都是由構造函數創建。
- 每個函數都會有
prototype
,當函數使用new
時被作為構造函數使用,返回一個對象。 - 每個對象裡都有隱藏式的
__proto__
來指向構造函數的prototype
。 - 每個
prototype
裡都有指向它自己prototype
,這叫做prototype chain
Prototype chain 裡如何尋找您的 methods or properties?
JavaScript engine
會優先在對象裡找自有屬性- 如果沒有找不到,將會進入構造函數裡
prototype
裡尋找到匹配屬性名。 - 屬性沒有在
prototype
裡,JS engine
會根據chain
往下找。 - 通過
prototype chain
實現繼承情況下,尋找過程就會沿著prototype chain
繼續找。 - 直到
chain
結束,就是根Object
,會返回undefined
總結
Inheritance in JavaScript is when an object is based on another object. Inheritance allows us to reuse existing code, having objects take on properties of other objects.
When a function is called as a constructor using the new
operator, the function creates and returns a new object. This object is secretly linked to its constructor’s prototype
, which is just another object. Using this secret link allows an object to access the prototype's
properties and methods as if it were its own. If JavaScript does not find a particular property within an object, it will keep looking up the prototype chain, eventually reaching Object()
(top-level parent) if necessary.
We also looked at a few methods and properties that allow use to check the origins and references of objects and their prototypes, namely:
hasOwnProperty()
isPrototypeOf()
Object.getPrototypeOf()
.constructor