11

まず、JavaScriptはクラスレス言語であることを理解していると言いたいと思います。私のバックグラウンドは、クラスをサポートするすべての古典的なOOP言語であるJava、C ++、およびObjective-Cです。

私はWeb開発に進出しており、JavaScriptを試し、そのパターンを学んでいます。現在、JavaScriptでクラスをシミュレートするコンストラクターパターンを使用しています。

これが私の「練習」クラスです。

function Car( model, year, miles ) {
    this.model = model;
    this.year = year;
    this.miles = miles;

    var privateVarTest = 10;

    this.getPrivateVarTest = function() {
        return privateVarTest;
    }

    this.setPrivateVarTest = function( value ) {
        privateVarTest = value;
    }
}

Car.prototype.toString = function() {
    return this.model + " is a " + this.year + " model and has " + 
           this.miles + " miles.";
}

var myCar = new Car( "Ford Focus", "2006", "65,000" );
document.getElementById('notepad').innerHTML += '</br> Testing </br>';
document.getElementById('notepad').innerHTML += myCar.toString() + '</br>';
document.getElementById('notepad').innerHTML += myCar.model + '</br>';
document.getElementById('notepad').innerHTML += myCar.getPrivateVarTest() + '</br>';
myCar.setPrivateVarTest( 20 );
document.getElementById('notepad').innerHTML += myCar.getPrivateVarTest() + '</br>';

作成されたオブジェクトprototypeごとに関数の新しいバージョンをインスタンス化しないため、関数を定義する方法を使用するのが好きです。Carただし、従来のOOP言語では、変数privateを作成publicし、必要に応じてこれらの変数を設定および取得するための関数/メソッドを作成します。

JavaScriptはクラスレスなので、この使用法にはキーワードがないprivateか、キーワードがないので、変数を「偽造」する方法を試してみようと思いました。そのとき、必須の代わりに使用すると、外部からアクセスできなくなりますが、私は私ができるゲッターとセッターを定義することができます。publicprivatevarthisconstructor

さて、私の質問の最後に、長い間終わってすみません。経験豊富なJavaScriptプログラマーによるベストプラクティスの場合private、他のOOP言語の標準に従うようにすべての変数を作成し、ゲッターとセッター(各オブジェクトの作成を強制するためにプロトタイプ化することはできません)を設定しますか、それともthisキーワードを使用すると、基本的に必要なものをすべて取得して設定できprivate、クラスに必要な内部データのハードコーディングにのみ使用できますか?

これをお読みいただき、ディスカッションにご参加いただきありがとうございます。経験豊富なWeb開発者がベストプラクティスとして使用している標準の感触をつかもうとしています。

4

3 に答える 3

23

一般OOP

私は、コードを書いている言語に関係なく、ゲッターとセッターはほぼ完全に無意味でばかげていると考えています。

ほとんどの場合、オブジェクトのプロパティは通常オブジェクトのドメイン内にある必要があるため、公開されたプロパティはまれである必要があります.何かを変えること。確かに例外はありますが(常に存在します)、最後に作成する必要があったのはいつだったか思い出せません。

さらに、プロパティが公開されている場合、メソッドで公開する唯一の理由は、言語の制約 (Java) のためにプロパティを公開できないか、そのプロパティを変更するときに何らかの検証または通知を行う必要があるためです。実際にプロパティを変更または返すだけの Java Bean スタイルのメソッドを追加するだけでは、カプセル化を維持することはできません。可能であれば、プロパティを公開することもできます。

しかし、どこからでもすべてを意のままに取得/設定したい場合の本当の問題は、基本的にチェーンされた手続き型コードを記述し、それを OOP と呼んでいるということです。あなたはまだ、次から次へと起こるという観点からのみ推論できる、長く曲がりくねった一連の事柄を持っています. OOP の考え方は、その長く巻きつくスパゲッティ チェーンを回避することです。これにより、重要なポイントで互いに相互作用する特定のドメインを所有するより大きな構造の観点からアーキテクチャをより多く見ることができます。それがなければ、少なくとも関数を名前空間の下に分類することでスパゲッティを少し減らしているので、どこを探すべきかを簡単に知ることができますが、OOP がアーキテクチャに提供できる重要な利点を実際には活用していません。

プライベートまたは JS の場合はローカル コンストラクター/ファクトリ クロージャー変数の真の価値は、意図を伝えることです。それが公開されている場合、外部の何かが実際にそれを変更しているはずです。そうでない場合は、var がオブジェクトの役割にすぎないことを明確にしています。

JS OOP

私のアドバイスは、JS でのクラス エミュレーションを忘れることです。それは完全に不要です。プロトタイプは、理解すればエレガントで簡単です。コンストラクターのプロトタイプ プロパティは一種のバックアップ オブジェクトと考えてください。存在しないインスタンスでメソッドを呼び出す場合、次のステップは、インスタンスのコンストラクターのプロトタイプ オブジェクト プロパティを確認することです。そのオブジェクトにそれがない場合、そのコンストラクターのプロトタイプ オブジェクトがチェックされ、最終的にコア オブジェクト コンストラクターのプロトタイプに到達するまで続きます。

コンストラクターにその場で新しいメソッドを追加し、ビルド後にすべてのインスタンスにそれを「継承」させることができるのは、そのルックアッププロセスのためですが、実際にはフォールバックプロセスほど継承ではありません。

JS での継承は非常に簡単です。それはあなたがそれをたくさんするべきだという意味ではありません。カスケード継承の長い連鎖は、正当な理由でどの言語でもアンチパターンと見なされます。また、コールバック プロセスの動作方法により、18 レベルのプロトタイプを通じて呼び出しオブジェクトを叩いている場合、パフォーマンスを実際に殺すこともあります。 JSのすべての小さなこと。継承よりも複合オブジェクトを好むと思います。継承の方が賢明な選択肢のように思われる場合は、チェーン内の 2 ~ 3 個を超えるプロトタイプ リンクを介して継承する誘惑に駆られたら、いつでも自分自身を確認してください。

ああ、それから、コンストラクターのローカル インスタンス変数をプライベート プロパティとして注意する必要がある JS の落とし穴が 1 つあります。これは、関数スコープ コンテキスト内で実際に動作している JS のクロージャー ルールにすぎません。プロトタイプまたはコンストラクター関数の外部で宣言されたメソッドは、これらの内部変数にアクセスできません。new キーワードで呼び出されたコンストラクター関数は、「this」がアクセスするもののルールを変更し、インスタンスを残しますが、それ以外の場合は他の方法で JS 関数を実行します。

JS OOP で理解する価値のあるクレイジーで強力な他のフレーバーは、apply、call、および now bind メソッドです。私はこれらを工場に必要なものと見なす傾向がありますが、非常に強力です。

JS OOP をマスターしたら、機能的な観点から JS を理解し始めると、非常に強力な 1-2 パンチ コンボが進行していることに気付くでしょう。JS の最小限のコードで非常に簡単に、ほぼすべてのことを行うことができます。設計上のトレードオフは、パフォーマンス (最新の JIT コンパイラーが驚くほどうまく処理している) であり、それがあなたを苦しめるためのロープをたくさん与えてくれることです。私はロープの方が好きです。自己リンチは楽しいものではありませんが、それはより良い本能を学習/開発するプロセスの一部であり、結果としてはるかに速く起こり、長期的にはより保守しやすいコードにつながります. Javaは基本的にOOPの実装を強制しますが、開発者が自分自身に愚かなことをすることに関して過度に保護主義的であるため、OOPの要点に完全に反する慣行がコミュニティ全体で採用される結果になります。

短いバージョン:

  • 言語に関係なく、大量の取得/設定をやめてください。そもそもOOPを実装することの勝因を大幅に減らします。
  • プロトタイプは本当にシンプルでエレガント、そしてパワフルです。それらをいじくり回します。それらを学びます。しかし、注意してください。比較すると、クラスは古臭く、不器用で、やり過ぎだと感じ始めるかもしれません (ただし、公平を期すために、非インタープリター言語では完全に必要です)。
  • JS がうまく機能するようにするには、たまたま扱っているあらゆる側面から独学で学んでください。生のエレガントな言語力という見返りは、費やした時間以上の価値があります。JSは、あなたがリストした言語よりもSchemeに近いので奇妙ですが、恣意的に、または設計原則を念頭に置いていなくても奇妙ではありません.Web UIでのJSの支配的な成功は偶然ではありません。それと」あなたは信じているでしょう。
  • 完全な開示: 私は Java が好きではありません。

アップデート:

es6 class キーワードは、JS の OOP に関して事実上何も変更しません。100% シンタックスシュガーです。IMO、「クラス」という言葉の使用は初心者には有利ではありませんが、JS でのオブジェクト コンストラクター/作成およびオブジェクト インスタンス化の 3 つのスタイルすべてに利点/欠点があり、それらはすべて知っている/理解する価値があります。これら 3 つのアプローチは、コンストラクターとしての関数、Object.create、そして今では class キーワードです。

于 2012-12-05T16:56:07.673 に答える
1

私たちは、新しく学ぶすべての言語が、最後に学んだ言語と同じように動作することを望む傾向があることに注意する必要があります。または最初。などなど。Douglas Crockford は素晴らしい (少し時代遅れではありますが) google talkを持っています。その中で彼は、「Javascript は、私が知っている唯一の言語であり、人々はそれを使用する前に学ぶ必要がないと感じています」と語っています。その講演は、あなたがここで尋ねたものを含め、あなたが知らなかった多くの質問に答えます.

セッターとゲッターを書くことに問題はありません。自分の正気を保つために仕事をすることに害があることはめったにありません。JS を話すとき、たまたま「C のアクセント」を持っているかもしれませんが、少なくともコードを読んでいる人には、あなたの意図が明確になります。

スコープ全体で「this」を管理するための私の正気を保つためのヒントは、新しいコンテキストに入る前に現在の「this」を保存できることを常に覚えておいてください。

var self = this;

宣言のスコープ内にオブジェクト メソッドを含めることで、特別な場合を除き、プロトタイプの使用を避けています。

function MyClass(_arg){
    var self = this;
    this.arg = _arg;

    this.returnArg = function(){
         return self.arg; 
    }
}

var foo = new MyClass("bar");
foo.returnArg();  //"bar"
于 2012-12-05T15:48:19.773 に答える
0

OOPの場合、実際にはjavascriptがある程度のOOPを提供していると言わざるを得ません。

つまり、OOP 設計の 4 つの主要な概念は JavaScript で実装できるということですが、Java や C++ のように強力ではなく、非常に明確に定義されているわけではありません。これらの概念を確認してみましょう。それぞれの例を示します。

1- 抽象化: ここで前に述べたように、Java のように OOP があまり明確に定義されていない理由を理解できます。 Java などの他の OOP 言語。

2-カプセル化:ここでは例で十分だと思います

function Student (stdName, stdEmail, stdAvg) {
  this.name = theName;
  this.email = theEmail;
  this.avg = stdAvg;
 }

ここでもご覧のとおり、関数を使用して「クラス」のような概念を定義しています。

3,4 - 継承とポリモーフィズム: JavaScript が継承とポリモーフィズムを実現する方法は、Java や C++ とは異なります。これは、そのプロトタイプ (正直なところ、他に言い方がわかりません) のアプローチによるものです。

const Gun = function(soundEffect){
  this.soundEffect = soundEffect;
};

Gun.prototype.fire = function(){
  console.log(this.soundEffect);
};

const DesertEagle = function(color,clipSize){
  this.color = color;
  this.clipSize = clipSize;
};

DesertEagle.prototype = new Gun("pew pew peeeew");

const myWeapon = new DesertEagle("black",15);

myWeapon.fire();

ここで、変数と関数のパブリック/プライベート アクセスをカバーするために、そのような概念を実装するために何らかの手法を使用する必要があります。以下のコードを確認してください。

const Student = function(name, stdNumber, avg){
  this.name = name;
  this.stdNumber = stdNumber;
  this.avg = avg;
  var that = this; //NOTE : we need to store a reference to "this" in order for further calls to private members

  this.publicAccess = { // a set of functions and variables that we want as public
    describe: function () {
       console.log(that.name + " : " + that.stdNumber);
    },
    avg: this.avg,
  };

  return this.publicAccess; // return set of public access members
};


const newStd = new Student("john", "123", "3.4");

newStd.describe();
// output: john : 123
console.log(newStd.avg)
// output: 3.4

ES6 では、クラスの定義ははるかに簡単ですが、それは単なる構文糖衣であり、その中心にあるものは同じです。

役立つことを願っています。また、この記事 ( Javascript デザイン パターン) もお勧めします。この記事では、avascript の機能とデザイン パターンに関する役立つ情報が提供されます。

私の下手な英語についてお詫び申し上げます。

于 2017-08-22T09:39:04.707 に答える