2

私は C# プログラミング言語の経験がありますが、現在 JS も使用する必要があり、私にとってはかなり新しいものです。

次のように、JS で単純なクラス エミュレーションを開発しようとしました。

http://jsfiddle.net/T74Zm/

function A( inputValue ) {
    this.Init( inputValue );
    this.Print();
}
A.prototype = {
    value: null,
    Init: function( inputValue ) {
        this.value = inputValue;
    },
    Print: function () {
        console.log( this.value );
    }
}

var obj = new A(40);

で変数をカプセル化してみたのですvalueA.prototype、JavaScriptの仕様で全てのオブジェクトが使えるようになっているようです。

だから私の質問は:

1)。OOP/アクセス修飾子をサポートする静的言語に非常に近いカプセル化を作成するにはどうすればよいですか?

2)。privateたとえば、JSでいくつかのアクセス修飾子をエミュレートするにはどうすればよいですか?

4

3 に答える 3

7

継承を使用したい場合は、できません(少なくともAFAIK)。ただし、継承チェーンのないオブジェクトの場合、クロージャーを使用してまったく同じ効果を得ることができます。問題は、プロパティを実際に完全にプライベートにする必要があるかどうかです。

閉鎖が近づく

プライベートにしたい変数をクロージャーに含む関数を実行できます。これらのプライベート変数は、実際にはオブジェクトに属していませんが、オブジェクトのメソッドによってのみアクセスできます。例えば:

var getPersonInstance = function (name) {

    // Those are "private" properties
    var myName = name;

    return {
        getName: function () {
            return myName
        },
        setName: function (name) {
            myName = name;
        },
        sayHello = function () {
            alert('hello! my name is ' + myName);
        }
    }    
};

var person = getPersonInstance('Juan');
person.getName(); // Returns Juan
person.myName = 'Don Vito' // This sets the person.myName property, which is not the one in the closure
person.setName('John') // Works
person.sayHello(); // alert hello! my name is John

ここで確認できます:

http://jsfiddle.net/MLF7v/1/

コンストラクター関数の表記法に慣れている場合は、次のようにすることができます。

(未検証)

function Person(name) {
    // Anything that is not attached to this will be private
    var myName = name;


    this.getName = function () { return myName;};
    this.setName = function (newName) {myName = newName;};
    this.sayHello = function () {alert('hey there, my name is' + myName);};
}

プロトタイプは使用されず、メソッドはオブジェクトに直接コピーされるため、これは上記とほとんど同じです。

ただし、クロージャのアプローチはメモリと時間がかかり、最悪の場合、作業しているオブジェクトに実際には属していない変数を使用します...これは重要な「セマンティック」問題です (このプロップは属しますか)私にとって、またはそうでない? ) 継承が頭痛の種になります。この理由は、拡張オブジェクトのメソッドがそのプライベート疑似プロパティにアクセスできないか (スーパーオブジェクト クロージャで定義されていないため)、または「スーパーオブジェクト」から共通のプライベート変数にアクセスできるためです (メソッドはスーパーオブジェクトで定義されているため、スーパーオブジェクトのクロージャーにアクセスします)。それはナンセンスです。

「文化的」アプローチ

私の謙虚な意見では、カプセル化は、誰かがあなたのコードをいじるのを防ぐことはできません.このプロパティは外部から使用しないでください。」たとえば、プライベート プロパティの前に '_' を付けます。これは、それらがプライベート、保護、またはその他のものであることを意味しますが、それから離れていることを意味します。そして触れてはいけないものには触れない。

このアプローチは、最も単純で最も効率的であるだけでなく、プロパティがオブジェクト内にあり、クロージャーに限定されないため、継承チェーンを操作できます。

var Person = function (name) {
    this._name = name;
}
Person.prototype.sayHello = function () {...};
Person.prototype.getName = function () {...};
Person.prototype.setName = function () {...};
于 2013-11-13T08:23:33.320 に答える
6

カプセル化とは、ユーザーが何かにアクセスしないようにコンピューターが厳密に強制するという意味ではありません。これは、モジュールとクラスが互いの内部にアクセスしないようにするだけで実現できます。プログラムにそのプロパティがある場合は、カプセル化を使用しています。または、少なくとも、カプセル化が与えると言われているすべての利点を得ることができます-ジャガイモ、ポテト。

ヘルプが必要な場合は、アンダースコアの接頭辞などのドキュメントや規則を使用して、何が内部的かどうかをより簡単に知ることができます。

考えてみてください。「プライベート」を「パブリック」にグローバルに置き換えて、C# プログラムを再コンパイルした場合、まったく同じように機能します。そして、C# でも、必要に応じてプライベートにアクセスできることをどういうわけか無視しています.SetAccessible。あなたはそれで問題ないように見えますが、何が問題なのですか?

クロージャーを介した「プライベート」のエミュレーションは、解決するよりもはるかに多く、さらに悪い問題をもたらします。

また、権威の議論についてマーティン・ファウラーを引用します。

アクセス制御はアクセスを制御しない

プライベートなフィールドがある場合、他のクラスはそれを取得できないことを意味します。違う!本当に望むなら、ほぼすべての言語でアクセス制御メカニズムを無効にすることができます。通常、通過する方法はリフレクションです。理由は、デバッガーやその他のシステム ツールがプライベート データを表示する必要があることが多いため、通常はリフレクション インターフェイスを使用してこれを行うことができます。

C++ にはこの種のリフレクションはありませんが、C++ は基本的にオープン メモリであるため、直接メモリ操作を使用できます。

アクセス制御のポイントは、アクセスを防ぐことではなく、クラスがいくつかのものを自分自身に保持することを好むことを知らせることです。アクセス修飾子の使用は、プログラミングの多くのことと同様に、主にコミュニケーションに関するものです。

http://martinfowler.com/bliki/AccessModifier.html#AccessControlDoesNotControlAccess

于 2013-11-13T21:09:11.853 に答える
0

クロージャを使用して変数をカプセル化できます。

function MyObjectFactory() {
  var obj = {},
    count = 0;

  obj.getCounter = function () {
    return count;
  };

  obj.setCounter = function (val) {
    count = val;
  };

  obj.incrementCounter = function () {
    count++;
  };

  obj.decrementCount = function () {
    count--;
  };

  return obj;  
}

一般的な方法でプロパティのゲッターとセッターを模倣することもできます。

function MyOtherObjectFactory() {
  var obj = {}, props = {};

  obj.prop = function (name) {
    return props[name];
  };

  obj.setProp = function (name, val) {
    props[name] = val;
    // call other functions if you'd like
  };


  // or even better, have a single function that works getter and setter regarding the params
  obj.autoProp = function () {
    if (arguments[1]) {
      // setter
      props[arguments[0]] = arguments[1]; // do check first argument is a hashable value
    } else if (arguments[0]) {
      // make sure we have a key
      // getter
      return props[arguments[0]];
    }
  }
}

PS: プロトタイプを直接設定しないでください。プロトタイプ チェーンが壊れます。

于 2013-11-13T08:33:23.293 に答える