先知道個keyword:
__proto__
: javascript自己定義的變數,用來實現inheritance效果,有點類似像link listnode
的概念,連結其他的 prototype
javascript記憶體管理的配置:
class
儲存在 global底下- class的
prototype
放置在heap (即class底下的各種variable和function) instance
(ex var b = new B()) 的b儲存在 callstack(記憶體RAM裡面)
slogan
:在自己的scope裡面找不到要的函式或變數就跟自己的__proto__
要!
繼承範例:
1 | var Car = function(){ |
benz.numberOfWheels() 有此方法
每次呼叫Car.apply(this, arguments)時"複製"到子類別的物件上
初始化物件時較慢,在run time想要動態改變numberOfWheels()的實作時
無法影響已經創建的子類別或父類別instances.
以下為初始化較有效率的寫法:
1 | var Car = function () { |
numberOfWheels該方法已經被掛在 Car.prototype上,
所以並不像Car.apply上直接複製一份給子class們,而是子class去共用Car.prototype.numberOfWheels 這個方法。
- 優點:節省初始化的時間和提升效率
- 缺點:這種寫法不支援存取private property
javascript 類別、prototype以及reference中的__proto__所指向的關係示意圖:
圖片作者: Ben大大
假設 B class extend A;
let b = new B(); // b.__proto__ = B.prototype
let a = new A(); // a.__proto__ = A.prototype
let o = new Object(); o.__proto__ = Object.prototype
//對應到圖片左邊的b、a、o.
(先從圖片最左上角開始看
那 var b = new B();
b想要使用繼承A的 getValue() 函式,
那麼就得先找自己的 b.prototype 沒有的話 找 b.__proto__
= B.prototype
若b.__proto__
也沒有的話(即B.prototype)也沒有,
那麼找 B.prototype.__proto__
== A.prototype
在A.prototype
就會找到getValue()的函式!
如果又沒找到,那就最後找A.prototype.__proto__
== Object.prototype
若沒有那就找 Object.prototype.__proto__
== null 即找無該函式,compile告知發生錯誤);
Prototype inheritance 的好處
- Suitable in loosely typed environments, no need to define explicit types.
- Makes it incredibly easy to implement
singleton pattern
(compare JavaScript and Java in this regard, and you’ll know what I am talking about).
(why? 因為prototype inheritance提供??? 請看補充二)
- Provides ways of applying a method of an object in the context of a different object, adding and replacing methods dynamically from an object etc. (things which are not possible in a strongly typed languages).
Prototype inheritance的壞處
- No easy way of implementing private variables. Its possible to implement private vars using Crockford’s wizardry using
closures
, but its definitely not as trivial as using private variables in say Java or C#.
(因為__prpto__
會指向prototype的所有成員!故無法像class inheritance那樣避免繼承到有private
關鍵字的變數,故得用closure手法來避免繼承到_private變數)
Reference:
prototype based vs. class based inheritance
補充ㄧ:Function.prototype.apply
fun.apply(thisArg, [argsArray])
// 將一連串參數用array包起來:[argsArray],丟給fun函式處理
範例:
1 | function theFunction(name, profession) { |
補充二:用Closure實作Singleton模式
閉包觀念連結:==> 閉包是什麼??
先看範例程式碼
1 | var UniverseN; |
可以看出若利用了Prototype inheritance的特性,,將IIFE函式掛在UniverseN.prototype.IIFE上,使得之後宣告的物件不會在複製一份IIFE出來出來,讓IIFE只跑一次!
這樣就可以達成一個class (UniverseN) 只能宣告一次的物件 (uni9)。 如果在宣告出 uni10,他們都還是指向同一樣的instance(uni9.__proto__
== uni10__proto__
)
Reference:
JavaScript Design Pattern - Singleton 單體模式