2013-10-17 180 views
2

我知道有幾種模式可以使JavaScript成爲類似的類。
我想採取'延伸原型'的方式...簡單地說,它看起來更整齊。
在下面的例子中,我有一個類(基本上是功能)MetricsChart,我有幾個公共方法和一個私有方法(基本上是一種可重用的方法)
這裏從公共方法(drawOrAdd)我無法訪問私有方法(_convertArrayToTable),我該怎麼做?使javascript私有方法可以訪問它的公共方法

function MetricsChart(containerId, chartType) { 
    this._container = document.getElementById(containerId); 
    this._chartType = chartType; 
    this._isChartDrawn = false; 
    this._chartData = null; 

    var _convertArrayToTable = function (data) { 
     return google.visualization.arrayToDataTable(data); 
    } 
} 

MetricsChart.prototype.drawOrAdd = function(data) 
{ 
    if (!this.isChartDrawn()) { 
     var chart = new google.visualization.LineChart(this._container); 
     if (chart) { 
      var table = _convertArrayToTable(data); 
      console.log(table); 
      this._isChartDrawn = true; 
     } 
    } 
} 

MetricsChart.prototype.isChartDrawn = function() { 
    return this._isChartDrawn; 
} 

MetricsChart.prototype.getChartData = function() { 
} 

一種方式我無意中發現是封閉MetricsChart類本身內部的公共方法...
它爲我:),我可以在外面訪問的公共方法和公有方法可以訪問私有方法(達到目的)。 以下代碼... 這是對的嗎?我在做什麼工作?

function MetricsChart(containerId, chartType) { 
    this._container = document.getElementById(containerId); 
    this._chartType = chartType; 
    this._isChartDrawn = false; 
    this._chartData = null; 

    var _convertArrayToTable = function (data) { 
     return google.visualization.arrayToDataTable(data); 
    } 

    MetricsChart.prototype.drawOrAdd = function (data) { 
     if (!this.isChartDrawn()) { 
      var chart = new google.visualization.LineChart(this._container); 
      if (chart) { 
       var table = _convertArrayToTable(data); 
       console.log(table); 
       this._isChartDrawn = true; 
      } 
     } 
    } 

    MetricsChart.prototype.isChartDrawn = function() { 
     return this._isChartDrawn; 
    } 

    MetricsChart.prototype.getChartData = function() { 
    } 

} 

回答

4

所以,這裏有幾件事情,爲了瞭解你所做的準確。 首先:

function foo() { 
    var i = 0; 

    function bar() { 
     return true; 
    } 
} 

這裏發生的:每一個功能foo被調用時,它會在其範圍內的新變量i,和一個新的功能bar。功能bar和變量i都在其範圍內,這意味着他們當地:沒有辦法,有了這個代碼,訪問要麼ibar功能foo。此外,因爲一旦功能foo終止,則配置ibar

所以,這就是爲什麼你不能從你的「公共」方法訪問「私人」方法,我希望現在更清楚。函數訪問函數或變量的唯一方法是在同一範圍內共享引用。所以,這就是你在最後一個例子中所做的:你在定義你的「私有」方法的同一範圍內定義你的「公共」方法。這樣他們可以訪問對方。但是,你所做的方式有一個很大的缺點。如前所述,函數bar創建的每次函數foo被調用時。在「類」的例子,它的意思是:

function MyClass() { 
    function myprivate() {} 

    MyClass.prototype.mypublic = function() { return myprivate() } 
} 

這意味着,每一個你創建的MyClass實例時,您要創建兩個新的功能,而你重寫所有的時間原型你的班」。這遠非一個好方法。事實上,如果你有類似的東西:

var a = new MyClass(); 
var _mypublic = a.mypublic; 
var b = new MyClass(); 

console.log(_mypublic === b.mypublic) // false 
console.log(_mypublic === a.mypublic) // false too! 

所以,你猜對了,但你執行錯了。你需要的是一個「模塊模式」:現在你可以在nodejs中使用CommonJS模塊,或者在瀏覽器中使用AMD等等,但是基本思想被定義爲「範圍」並且只從你想要的範圍中導出。在你的情況下,你可以有:

// this is your "module" 
;(function(exports) { 
    // your local (private) function 
    var _convertArrayToTable = function (data) { 
     return google.visualization.arrayToDataTable(data); 
    } 

    function MetricsChart(containerId, chartType) { 
     this._container = document.getElementById(containerId); 
     this._chartType = chartType; 
     this._isChartDrawn = false; 
     this._chartData = null; 
    } 

    MetricsChart.prototype.drawOrAdd = function(data) { 
     if (!this.isChartDrawn()) { 
      var chart = new google.visualization.LineChart(this._container); 

      if (chart) { 
       var table = _convertArrayToTable(data); 
       console.log(table); 
       this._isChartDrawn = true; 
      } 
     } 
    } 

    // you decided to exports to the main scope what you want 
    exports.MetricsChart = MetricsChart; 

}(this)); // here `this` is the global object 

就是這樣。您已經使用「模塊模式」創建了一個閉包,並且可以通過「public」方法訪問「private」函數,因爲它們在相同的範圍內定義。但是因爲在「類」構造函數中不這樣做,所以每次實例化新對象時都不要重新定義它們。因此,這種寫法前面的例子中,將會給正確的結果:

var a = new MyClass(); 
var _mypublic = a.mypublic; 
var b = new MyClass(); 

console.log(_mypublic === b.mypublic) // true 
console.log(_mypublic === a.mypublic) // true 
+0

@零,感謝非常詳細的解釋,我知道我的方法有問題,你解釋了這個問題,我明白更好。要試試你給 – SridharVenkat

+0

的解決方案,謝謝你.. – SridharVenkat

0

訪問私有方法使用特權方法。檢查這個文件:http://javascript.crockford.com/private.html

關於你的代碼檢查這樣的回答: Setting javascript prototype function within object class declaration

附:

function Test() 
    { 
     var p = function(pv) 
     { 
      // 
     } 

     this.e = function (ap) { p(ap) } 
    } 
    var n = new Test(); 
    n.e("e"); // It is legal call 
    n.p(); // will throw 

但是,如果你在聲明一個私有函數C-TOR它會在第一次創建這種類型的對象來執行。在原型中聲明方法時,在執行任何代碼之前添加此方法。一般來說,瀏覽器首先檢查js文件以收集所有原型的方法並執行任何代碼。所以當你將一個原型方法聲明爲c-tor時,這些方法只有在首次創建這些類型的對象後纔可用。 ( 對不起我的英語不好 )。

檢查這種情況:

 function Test() 
    { 
     alert(this.ST_A);//alert undefined 
     alert(this.ST_B);//alert 2 
     Test.prototype.ST_A = 1; 
     alert(this.ST_A)//alert 1 
    } 
    Test.prototype.ST_B = 2; 

在第一遍瀏覽器將填充測試與ST_B和ST_B將可在任何地方任何時間。在第二遍之後,瀏覽器將開始執行代碼,此時ST_A將不可見,直到瀏覽器執行Test.prototype.ST_A = 1;

+0

但特權方法可以訪問外太.. – SridharVenkat

+0

它是可見的!我發佈示例 –

+0

是的,這也是我推斷的笏。但你不希望私人方法在外面可見(但希望它可以通過你的公共方法) – SridharVenkat

0

你所做的並不一定是「錯誤的」......它看起來很奇怪。另外,在創建「MetricsChart」實例之後,您將無法訪問「MetricsChart.prototype。*」。根據你如何使用這個對象,它可能並不重要。

話雖這麼說,另一種方式是保持原來的結構,但將以下的構造之外:

var _convertArrayToTable = function (data) { 
    return google.visualization.arrayToDataTable(data); 
} 

它仍然是專用於你的模塊應該是足夠好(你正在使用模塊是否正確?)。

+0

我對原型和閉包很新穎,沒有來到模塊......我沒有使用模塊。 – SridharVenkat

0

你所做的完美的作品。

您無法繼承任何OOP語言中的私有方法,以覆蓋它們或直接訪問它們。他們是私人的。所以將它們作爲繼承目的的原型是沒有意義的。你已經將它們包裝在功能範圍內,以便它們像他們所需要的那樣「私密」。