使用JavaScript闭包遇到的陷阱(一)

使用JavaScript闭包遇到的陷阱(一)

陷阱:在类的原型对象中添加特权方法

首先定义一个Page类,该类中有一个私有变量dom:

function Page(){
var dom;
}
定义2个特权方法来访问、修改私有变量dom:

function Page(){
var dom;
this.setDom=function(newDom){
dom=newDom;
};
this.getDom=function(){
return dom;
}
}
然后我们对Page类进行测试:

var page1=new Page();
page1.setDom("page1");
console.log(page1.getDom());//page1
var page2=new Page();
page2.setDom("page2");
console.log(page2.getDom());//page2
console.log(page1.getDom());//page1
到目前为止,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类进行测试:

var page1=new Page();
page1.setDom("page1");
console.log(page1.getDom());//page1
var page2=new Page();
page2.setDom("page2");
console.log(page2.getDom());//page2
/
注意!问题出现了!
/
console.log(page1.getDom());//page2
这时最后一行的console.log(page1.getDom())打印的结果变成了page2

探究

前提

  1. 在使用new操作符调用Page构造函数创建对象的过程:先创建一个Page类的空对象,并将构造函数中的this指向该对象,再执行构造函数。

  2. 在函数中定义的变量都保存在该函数执行环境变量对象中。

  3. 每个函数都有一个作用域链。函数在定义时,就会生成不完整的作用域链,该作用域的前端是函数定义时所在环境变量对象。函数在执行时,会创建该函数的执行环境,并将该执行环境的活动对象(这里可理解为变量对象)添加到之前创建的作用域链的前端,此时的作用域链是完整的作用域链。

  4. 变量访问的过程就是从作用域链家前端沿着作用域链查找变量的过程。

分析

  1. Page类的构造函数使用动态原型的方式来给原型对象添加方法。因此在创建第一个Page实例时,调用Page函数创建执行环境a,这时,会在a中定义setDom和getDom方法并添加到Page类的原型对象中。原型对象中的setDom和getDom方法的作用域链前端都是执行环境a(准确的说是a对应的变量对象)。

  2. 创建第一个Page实例时,给Page类的原型对象添加了setDom和getDom方法。之后再创建其他的Page实例时,都不会再修改原型对象中的setDom和getDom方法了。

  3. 在创建第二个Page实例时,再次调用Page函数,创建了执行环境b。

  4. 在调用Page实例的setDom或getDom方法时,由于都是调用原型对象中的方法。而根据之前说的,原型对象中的setDom方法和getDom方法在访问dom变量的时候,都要沿着作用域链查找,最后找到的是环境a中的变量dom,也就是第一个Page实例的私有变量dom。

  5. 所以在测试的时候,无论是page1还是page2调用setDom和getDom方法,都是修改或访问page1中的私有变量dom。

小结

在类的原型对象中添加的特权方法,不能用来访问或操作类的私有变量,只能用来访问或操作this修饰的特权变量。

关键字:产品经理, JavaScript


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部