局域值和繼承值
局域值和繼承值
當你存取物件屬性的時候,JavaScript 會進行這些步驟,如同本章前面所提到過的︰
- 檢查局域值是否存在。如果存在,就返回局域值。
- 如果局域值不存在,就檢查原型鏈(使用
__proto__
屬性)。 - 如果在原型鏈上的物件具有所求的指定屬性,就返回這個屬性的值。
- 如果找不到這樣的屬性,這個物件就不具有這個屬性。
這些步驟之後的結果,取決於你如何循著這個方式來定義。一開始的例子有這些定義︰
function Employee () { this.name = ""; this.dept = "general"; } function WorkerBee () { this.projects = []; } WorkerBee.prototype = new Employee;
藉由這些定義,假定你以如下語句建立 amy
作為 WorkerBee
的實體︰
amy = new WorkerBee;
amy
物件具有一個局域的屬性,projects
。name
和 dept
屬性的值並不是 amy
的局域值,所以是從 amy
物件的 __proto__
屬性得來的。因此,amy
具有這些屬性值︰
amy.name == ""; amy.dept == "general"; amy.projects == [];
現在假定你在與 Employee
連結的原型改變 name
屬性的值︰
Employee.prototype.name = "Unknown"
乍看之下,你可能會預期新的值會被向下傳播給 Employee
所有的實體。然而,事情並不如此。
當你建立 Employee
物件的任何實體,這些實體會取得 name
屬性的局域值(空字串的那個)。這意味著當你使用新建立的 Employee
物件來設定 WorkerBee
原型的時候,WorkerBee.prototype
就具有 name
屬性的局域值。因此,當 JavaScript 找到 amy
物件(WorkerBee
的實體)的 name
屬性的時候,JavaScript 在 WorkerBee.prototype
找到了這些屬性的局域值。也因此並不會進一步在鏈的上一層 Employee.prototype
裡尋找。
如果你想要在執行時期改變物件屬性的值,而且希望新的值能被這個物件的所有子孫所繼承,你就不能在物件的建構子函數中定義這個屬性。相對的,你要把這個屬性加入到與建構子相連結的原型。例如,假定你修改前面的代碼如下︰
function Employee () { this.dept = "general"; } Employee.prototype.name = ""; function WorkerBee () { this.projects = []; } WorkerBee.prototype = new Employee; amy = new WorkerBee; Employee.prototype.name = "Unknown";
在這個情況下,amy
的 name
屬性就會變成 "Unknown"。
如同這些範例所示,如果你希望物件的屬性有預設值,而且還希望能夠在執行時期修改這些預設值,你就應該在建構子的原型中設定這些屬性,而不是在建構子函數本身。