首先定義一個Page類,該類中有一個私有變量dom:javascript
function Page(){ var dom; }
定義2個特權方法來訪問、修改私有變量dom:前端
function Page(){ var dom; this.setDom=function(newDom){ dom=newDom; }; this.getDom=function(){ return dom; } }
而後咱們對Page類進行測試:java
var page1=new Page(); page1.setDom("<div>page1<div>"); console.log(page1.getDom());//<div>page1<div> var page2=new Page(); page2.setDom("<div>page2</div>"); console.log(page2.getDom());//<div>page2</div> console.log(page1.getDom());//<div>page1<div>
到目前爲止,Page類正常工做。
這時問題來了:我想每一個Page類的對象都有相同的特權方法,那就將這兩個特權方法添加到Page的原型對象中好了。閉包
function Page(){ var dom; if(this.__proto__.setDom !== "function"){ this.__proto__.setDom=function(newDom){ dom=newDom; }; this.__proto__.getDom=function(){ return dom; }; } }
對修改後的Page類進行測試:dom
var page1=new Page(); page1.setDom("<div>page1<div>"); console.log(page1.getDom());//<div>page1<div> var page2=new Page(); page2.setDom("<div>page2</div>"); console.log(page2.getDom());//<div>page2</div> /* 注意!問題出現了! */ console.log(page1.getDom());//<div>page2<div>
這時最後一行的console.log(page1.getDom())
打印的結果變成了<div>page2<div>
函數
在使用new
操做符調用Page
構造函數建立對象的過程:先建立一個Page
類的空對象,並將構造函數中的this
指向該對象,再執行構造函數。測試
在函數中定義的變量都保存在該函數執行環境的變量對象中。this
每一個函數都有一個做用域鏈。函數在定義時,就會生成不完整的做用域鏈,該做用域的前端是函數定義時所在環境的變量對象。函數在執行時,會建立該函數的執行環境,並將該執行環境的活動對象(這裏可理解爲變量對象)添加到以前建立的做用域鏈的前端,此時的做用域鏈是完整的做用域鏈。code
變量訪問的過程就是從做用域鏈家前端沿着做用域鏈查找變量的過程。對象
Page
類的構造函數使用動態原型的方式來給原型對象添加方法。所以在建立第一個Page
實例時,調用Page
函數建立執行環境a,這時,會在a中定義setDom
和getDom
方法並添加到Page
類的原型對象中。原型對象中的setDom
和getDom
方法的做用域鏈前端都是執行環境a(準確的說是a對應的變量對象)。
建立第一個Page
實例時,給Page
類的原型對象添加了setDom
和getDom
方法。以後再建立其餘的Page
實例時,都不會再修改原型對象中的setDom
和getDom
方法了。
在建立第二個Page
實例時,再次調用Page
函數,建立了執行環境b。
在調用Page
實例的setDom
或getDom
方法時,因爲都是調用原型對象中的方法。而根據以前說的,原型對象中的setDom
方法和getDom
方法在訪問dom
變量的時候,都要沿着做用域鏈查找,最後找到的是環境a中的變量dom
,也就是第一個Page
實例的私有變量dom
。
因此在測試的時候,不管是page1
仍是page2
調用setDom
和getDom
方法,都是修改或訪問page1
中的私有變量dom
。
在類的原型對象中添加的特權方法,不能用來訪問或操做類的私有變量,只能用來訪問或操做this
修飾的特權變量。