使用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("<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类进行测试:

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>

探究

前提

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

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

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

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

分析

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

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

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

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

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

小结

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值