8/02/2013
4:53:00 PM 0

Javascript Prototype Chain

Javascript 使用 prototype 來達到類似其他語言的繼承概念, 要了解 Javascript 的繼承, 首先要了解 prototype chain, 當我們建立一個 Javascript 物件, 並使用 Javascript 屬性時, 會先從物件內部所擁有的屬性開始尋找, 如果找不到屬性的名稱,就會從 prototype 所指向的物件繼續搜尋, 一層一層的往內搜尋, 這就是原型鏈搜尋

首先我們使用 function 來建構一個物件 (Object Constructor)
function Earth(){};
接著建立一個物件實例(Object Instances)
var e1 = new Earth();
建立實例的過程中不單單是設定 name 屬性, 還把 Employee 所繼承的物件帶給 e1

new 的動作相當於
    var e1 = {};
    e1.__proto__ = Earth.prototype;//__proto__  Non-standard
    Earth.call(e1);
使用 Chrome Developer Tools 可看出 e1 的屬性和方法










測試 e1.constructor (關於 constructor 參考 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor)
> e1.constructor
[Function: Earth]
e1 沒有 constructor 屬性, 所以往內部查找 __proto__ 正好有這屬性, 所以輸出 __proto__.constructor, 由此可推論  e1.constructor == e1.__proto__.constructor
> e1.constructor == e1.__proto__.constructor
true
> Earth.prototype.constructor == e1.constructor
true
從上面的例子可看出 prototype 屬性會決定繼承的物件, 改變 prototype 屬性後, 再 new 出來的物件繼承關係也跟著改變


接下來說明 instanceof, instanceof 在 Java 中也有這個功能, 作用也類似,
Javascript 的 instanceof 會從 prototype chain 查找, 是否包含建構物件的 prototype, MDN 中有實做出類似 instanceof  內部運作的方式, 可參考 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model?redirectlocale=en-US&redirectslug=JavaScript%2FGuide%2FDetails_of_the_Object_Model#Determining_instance_relationships

做個綜合測試
> function X(){}
undefined
> X.constructor //所有 function 都是 Function object
function Function() { [native code] }
> X.prototype.constructor //參考到 X
function X(){}
> var o1 = new X()
undefined
> o1 instanceof X
true
> o1.constructor //等於 o1.__proto__.constructor
function X(){}
> X.prototype = [] //改變 X.prototype 參考到陣列
[]
> var o2 = new X()
undefined
> o1 instanceof X // 相當於 o1.__proto__ == X.prototype
false
> X.prototype.isPrototypeOf(o1);
false
> o2 instanceof X // 相當於 o2.__proto__ == X.prototype
true
> o1 instanceof Array
false
> o2 instanceof Array
true
> X.constructor
function Function() { [native code] }
> X.prototype.constructor
function Array() { [native code] }
> o1.constructor
function X(){}
> o2.constructor
function Array() { [native code] }
所有 function 都是 Function object 的實例, 所以 X.constructor 指向 Function, X.prototype.constructor 指向 X,
建立物件會沿著 prototype chain 尋找, 因此
 var o1 = new X();
相當於
    var o1 = {};
    o1.__proto__ = X.prototype;//reference X
    X.call(o1);
而 X.prototype = []; 改變了 prototype 的參考對象, 因此 X 的 prototype chain 改變了
    var o2 = {};
    o2.__proto__ = X.prototype;//reference Array
    X.call(o2);
要怎麼讓 o1 instanceof X 變成 true 呢? 只要讓 o1.__proto__ 和 X.prototype 一致就行了
> o1.__proto__ = X.prototype;
[]
> o1 instanceof X;
true
> X.prototype.isPrototypeOf(o1);
true

0 comments:

Post a Comment