2

JavaScriptを「クラスのように」するパターンがいくつかあることを理解しています。
「プロトタイプによる拡張」の方法を取りたいと思います...単にbcozの方がきれいに見えます。ここではパフォーマンスについてあまり心配していません...
以下の例では、クラス(基本的に関数)MetricsChartがあり、いくつかのパブリックメソッドと1つのプライベートメソッド(基本的に再利用可能なメソッド)があります
ここでは、パブリックメソッド(drawOrAdd)から私プライベート メソッド (_convertArrayToTable) にアクセスできません。どうすればアクセスできますか?

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 () {
}

私が偶然見つけた方法の 1 つは、パブリック メソッドを 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

4 に答える 4

4

それで、あなたが何をしたかを正確に理解するために、ここにいくつかのことがあります。初めに:

function foo() {
    var i = 0;

    function bar() {
        return true;
    }
}

ここで何が起こっているか: 関数が呼び出されるたびfooに、スコープ内に新しい変数iと新しい関数が作成されますbar。関数barと変数iはそのスコープ内にあり、それはそれらがlocalであることを意味します: このコードでは、 function のいずれかに、iまたはそのbar 外部fooにアクセスする方法はありません。また、関数fooが終了すると、iとの両方barが破棄されるためです。

これが、「パブリック」メソッドから「プライベート」メソッドにアクセスできない理由です。これがより明確になったことを願っています。関数が関数または変数にアクセスする唯一の方法は、同じスコープ内で共有される参照があることです。したがって、これが最後の例で行ったことです。「プライベート」メソッドを定義するのと同じスコープで「パブリック」メソッドを定義します。このようにして、それらは相互にアクセスできます。ただし、あなたが行った方法には大きな欠点があります。前に述べたように、関数barは関数が呼び出されるたびに作成されます。foo「クラス」の例では、次のことを意味します。

function MyClass() {
    function myprivate() {}

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

これは、 のインスタンスを作成するたびにMyClass、2 つの新しい関数を作成し、「クラス」のプロトタイプを常に書き直していることを意味します。これは良いアプローチとは言えません。実際、次のようなものがある場合:

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

以上です。「モジュールパターン」を使用してクロージャーを作成しました。「パブリック」メソッドから「プライベート」関数にアクセスできます。これらは同じスコープで定義されているためです。ただし、「クラス」コンストラクターでそれを行わないため、新しいオブジェクトをインスタンス化するたびにそれらを再定義する必要はありません。したがって、このように記述された前の例では、正しい結果が得られます。

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

console.log(_mypublic === b.mypublic) // true
console.log(_mypublic === a.mypublic) // true
于 2013-10-17T07:24:40.723 に答える
0

プライベート メソッドにアクセスするには、特権メソッドを使用します。このドキュメントを確認してください: http://javascript.crockford.com/private.html

あなたのコードについては、この答えをチェックしてください: オブジェクトクラス宣言内でjavascriptプロトタイプ関数を設定する

ps

    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;

最初のパスで、ブラウザーは Test に ST_B を入力し、ST_B はいつでもどこでも使用できるようになります。2 回目のパスの後、ブラウザはこの時間内にコードの実行を開始します。ブラウザが Test.prototype.ST_A = 1; を実行するまで、ST_A は表示されません。

于 2013-10-17T06:54:55.917 に答える