1

私は Douglas Crockford の本「JavaScript : The Good Parts」と他の多くのリソースを読みましたが、Javascript での継承とプライバシーの実装について少し混乱しています。

私は Java World から来ました。クロージャーを介してプライバシーをシミュレートしたり、プロトタイプを介して継承を行ったりできることを理解しましたが、JavaScript の方法でそれを行いたいと考えています。

プロトタイプ/寄生パターンでいくつかの継承を実行できることはわかっています。これはパフォーマンスには適していますが、一部のプライバシー メンバーを適切に使用する方法はありません (新しいオブジェクトがインスタンス化されるたびに何らかのクロージャ関数を作成する必要があります)。

オブジェクトから継承し、douglas Crockford によって提案されたような機能/寄生パターンを介してプライバシー メンバーを使用できることはわかっていますが、オブジェクトがインスタンス化されるたびに関数が再度作成されるため、明らかにパフォーマンス/メモリの問題があります。

最後に、プライバシーのカプセル化などの他の言語での優れたプラクティスが JavaScript で意味があるかどうか疑問に思っています。ここで、「私たちはプライバシーを気にしません。このプロパティに外部からアクセスしてはならないことを世界に伝えてください。それで十分です」と人々が言っ​​ている投稿を見たことがあります。

Javascript の優れたプラクティスは、パブリック インターフェイスを使用したプロトタイプ/寄生継承に縮小され、開発者が期待どおりにライブラリを使用することを期待する必要がありますか? それとも、継承とカプセル化の観点から考えるのは、javascript ではなく「java」の考え方でしょうか? これらの目標を達成するために、JavaScript でアヒルのプログラミングの力を使用するにはどうすればよいでしょうか。

4

2 に答える 2

2

JavaScript でプライベート データを安全に継承する方法

多くの場合、アンダースコアを使用して、プロパティまたはメソッドをプライベートと見なす必要があることを示します。それは悪い考えです。

アンダースコアが悪い考えである理由

アンダースコアはデータのプライバシーを保証するものではなく、いくつかの重要な問題を引き起こします:

  1. 初心者はアンダースコアの意味を知らないので、アンダースコアを無視します。
  2. 上級ユーザーは、自分が何をしているかを理解していると考えているため、アンダースコアは適用されません。
  3. 実装の詳細が変更される可能性があり、アンダースコア プロパティを使用したユーザー コードのコードが壊れる可能性があります。

カプセル化はオブジェクト指向設計の重要な機能であるため、これらは問題です。オブジェクトは、特定の問題を解決するために存在します。プライベート メソッドは、実装の詳細としてのみ関連する問題を解決する場合があります。実装の詳細はパブリック インターフェイスよりも変更される可能性が高いため、実装の詳細に依存するコードは、実装の詳細が変更されると壊れる可能性があります。

パブリック インターフェイスのみを公開すると、変更される可能性のある実装の詳細が隠され、サポートされていない実装の詳細ではなく、サポートされている機能にユーザーが依存するようになります。

真のデータプライバシーのために機能継承を使用する

機能継承を使用して、プライベート データを継承できます。

機能継承は、オブジェクト拡張関数をオブジェクト インスタンスに適用することによって機能を継承するプロセスです。この関数はクロージャー スコープを提供します。これは、関数のクロージャー内にプライベート データを隠す効果があります。

Douglas Crockford は、「JavaScript: The Good Parts」でこの用語を作り出しました。Crockford の例では、子ファクトリは既存の基本ファクトリからオブジェクトをインスタンス化する方法を認識しており、継承階層を作成する効果があります。しかし、それは悪い考えです。クラスの継承よりも、常にオブジェクトの構成を優先する必要があります。

基本オブジェクトをパラメーターとして受け取るようにパターンをわずかに変更することで、機能的な mixin を作成および構成できます。

関数 mixin は、提供されたオブジェクト インスタンスを拡張します。関数のクロージャ スコープには、プライベート メソッドとデータが含まれる場合があります。その後、その関数内で特権メソッドを公開できます。それはこのように動作します:

const withFlying = instance => {
  let canFly = true; // private data
  let isFlying = false;

  // Privileged method
  instance.fly = () => {
    isFlying = canFly ? true : isFlying;
    return instance;
  };

  // Privileged method
  instance.land = () => {
    isFlying = false;
    return instance;
  }

  // Privileged method
  instance.getFlightStatus = () => isFlying ? 'Flying' : 'Not flying';

  return instance;
};

// Create a new object and mix in flight capability:
const bird = withFlying({});
console.log(bird.fly().getFlightStatus()); // true

bird.land();
console.log(bird.getFlightStatus()); // false

機能的な mixin は、標準の関数構成を使用して、他の基本オブジェクトおよび他の機能のセットと一緒に構成できます。まず、compose 関数が必要です。compose()Lodash、Ramda、または標準の構成関数を提供する関数型プログラミング ライブラリから使用できます。または、独自に作成することもできます。

// Function composition: Function applied to the result of another function application, e.g., f(g(x))
// compose(...fns: [...Function]) => Function
const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x);

標準の関数構成を使用して、任意の数の mixin を一緒に構成できるようになりました。

// This function returns a function which can be used
// as a functional mixin.
// `text` here is private data that determines the sound
// `quack()` will log to the console.
const withQuacking = text => instance => {
  // Privileged method
  instance.quack = () => console.log(text);
  return instance;
};

// Compose mixins:
// ('Quack!' is private data)
const createDuck = compose(withFlying, withQuacking('Quack!'));

const malard = createDuck({});

console.log(malard.fly().getFlightStatus()); // Flying
malard.quack(); // "Quack!"

さまざまな継承手法を使用してファクトリ関数を構成するより汎用的な方法については、スタンプ仕様を参照してください。

参考文献:

于 2013-09-10T08:42:54.043 に答える