首先定义一个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
修饰的特权变量。