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

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

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

首先定义一个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>函数

探究

前提

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

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

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

  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修饰的特权变量。

相关文章
相关标签/搜索