使用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修飾的特權變量。

相關文章
相關標籤/搜索