15

「JavaScript は世界で最も誤解されている言語です」-D.Crockford

私の質問:

  1. コンストラクターとプロトタイプは平易な英語で?
  2. プロトタイプを使用する必要性は何ですか? プロトタイプとコンストラクターを使用する目的は何ですか? つまり、柔軟性が向上します。私は過去 6 か月間この言語を使用しており、プロトタイプとコンストラクターを使用する状況は一度もなかったので、これを尋ねています。

構文や説明の仕方を探しているわけではありません。それらが何であるかの一部を理解しているので、これらのことをより簡単な方法で知りたかっただけです。類推 (非技術) または例は素晴らしいでしょう.*

この質問をした理由の詳細 (無視したい場合は無視してください):

私は過去 6 か月間 JavaScript を使用してきましたが、JavaScript がプロトタイプベースの言語であることを知ってショックを受けました。

JavaScript の使用方法に関するスタック オーバーフローの質問をいくつか調べたところ、プロトタイプとコンストラクターに出くわしました。

私はそれを学びました。今では、コンストラクターやプロトタイプに関しては初心者ではないと言えます。私は構文に精通しています。しかし、それでも私は何かが欠けていると思いますし、この言語の核心に迫っていません。時々混乱します。

私がはっきりしていることを願っています。

4

8 に答える 8

7

まず最初に、彼自身 (Crockford) をフィーチャーしたこのプレイリストをご覧になることをお勧めします。古いかもしれませんが、JavaScript の「ロジック」を非常によく説明しており、あなたの質問は特に 3 番目のビデオで回答されています。

質問の冒頭で投稿したクロックフォードのコメントもターゲットにしたいので、他の従来のオブジェクト指向プログラミング言語でオブジェクトがどのように描かれているかを説明することから、この質問への回答を開始します。

コンストラクターを理解するには、まずオブジェクトをよく理解する必要があります。従来の OOP 言語では、オブジェクトは、オブジェクトの状態を記述する変数 (プロパティまたはフィールドと呼ばれる) と、オブジェクトの動作を記述する関数 (メソッドと呼ばれる) のコレクションです。これらの (JavaScript 以外の) 言語では、これらのオブジェクトの「設計図」はクラスと呼ばれます。

したがって、Java で Human クラスを作成すると、非常に単純化して次のようになります。

class Human {
    String name;
    int weight; // kg
    int height; // cm

    void eat(int foodWeight) {
        this.weight += foodWeight;
    }

    Human(int weight, int height, int name) {
        this.weight = weight; 
        this.height = height;
        this.name   = name;
    }
}

そして、上記の「設計図」を使用して、次のようにオブジェクトを作成します。

Human Joe = new Human(90, 180, "Joe");

そして今、体重が 90 kg で身長が 180 cmJoe の のインスタンスであると言います。 Human

上記のクラスではHuman()、オブジェクトを作成し、作成時の状態を定義するために使用される関数があることに気付きました。これは基本的にコンストラクターが行うことです。

では、JavaScript の違いは何でしょうか?

作成時に大衆にアピールするために (私が投稿したビデオ シリーズで聞くことができます)、JavaScript には Java に似た構文が組み込まれています。Crockford 氏によると、これによって実現したことは、プログラマーは Java をある程度知っている/学んでいるので、新しいコマンドをいくつか覚えてから JavaScript でプログラミングすることができるという考えをプログラマーに与えることです。 2つは類似点をはるかに上回ります。

JavaScript では、Java クラスのように見える方法でオブジェクトを作成するには、次のような関数構文を使用します。

var Human = function(name, height, weight) {
    this.name   = name;
    this.height = height;
    this.weight = weight;

    this.eat    = function(foodWeight) {
        this.weight += foodWeight;
    };
};

そして、Joe上で行ったように定義したい場合は、次のようにします。

var Joe = new Human("Joe", 180, 90);

示されている Java 構文と JavaScript 構文の類似点を見ることができます。最初の質問に答えると、JavaScript コンストラクターは、 で呼び出されたときにnew、 が指す暗黙的に作成されたオブジェクトを作成して返す関数ですthis

では、プロトタイプの出番はどこでしょうか? さて、JavaScript では、関数も JS オブジェクトそのものであり、 というプロパティがありますprototype。したがって、Human()上で作成したコンストラクタには というプロパティがあり、このプロパティは、 の他のすべてのインスタンスと同様に、prototypeプロパティとメソッドが によって継承されるオブジェクトを参照します。このオブジェクトは、継承されるプロパティを作成するために拡張できます。それらすべてのインスタンスによって。JoeHuman

たとえば、 のメソッドの 1 つにFunction.prototype有名なtoStringメソッドがあります。あなたが定義することができます

Human.prototype.toString = function() {
    return this.name + " is " + this.height + " cm tall and weighs " + this.weight + " kg";
}

次に、 を呼び出すJoe.toString()alert(Joe)、自動的に を呼び出すようなことをするとtoString()、返される値は「ジョーは身長 190 cm、体重 80 kg」になります。

あなたの質問の文脈でカバーできる OOP と JavaScript についての詳細は他にもたくさんありますが、私の答えは十分に長いと思います! これがあなたの質問に答えることを願っています。

于 2013-08-26T19:11:58.147 に答える
4

コンストラクターとプロトタイプは平易な英語で?

「コンストラクター」という名前が示すように、コンストラクターは何か新しいもの (オブジェクト) を作成し、作成するものはすべてテンプレート (プロトタイプ) に従います。

JavaScript では、通常の関数呼び出しとは異なる方法で呼び出すだけで、任意の関数をコンストラクターとして使用できます。例えば:

function Foo()
{
}

Foo(); // normal function call, returns nothing
var f = new Foo(); // constructor call, returns a new Foo object

alert(f instanceof Foo) // "true"

前述のとおり、プロトタイプはテンプレートのようなものです。実行時にプロトタイプを変更でき、変更はそのプロトタイプから継承するすべてのオブジェクトに影響します。.prototypeオブジェクトのプロトタイプには、コンストラクターのプロパティを介してアクセスできます。例えば:

var f = new Foo();
Foo.prototype.bar = 'baz';

alert(f.bar) // "baz"

プロトタイプを使用する必要性は何ですか? プロトタイプとコンストラクターを使用する目的を理解したいですか? つまり、柔軟性が向上します。

プロトタイプは、クラス指向言語に期待されるものと同様に、メソッドとプロパティを使用して共有の動作やデータを定義するために使用されます。それらは相互に継承することもでき、 までのプロトタイプのチェーンを作成しObjectます。関数でさえ、実際にはFunctionオブジェクトです。

プロトタイプがなければ、すべての作業をコンストラクター内で行う必要があります。

function Foo()
{
    // add methods and data
    this.bar = 'baz';
}

上記の例では、直接的なメリットは見られないかもしれませんが、いくつかあります:

  1. メモリー; 各オブジェクト インスタンスにメソッドを追加すると、プロトタイプ チェーンを介してメソッドを使用可能にするよりも多くのメモリが消費されます。プロトタイプ チェーンをトラバースする必要がないという利点は、通常、オブジェクトのインスタンス化にかかる時間によって平準化されます。

  2. 階層; プロジェクトが大きくなると、最終的にある種のオブジェクト階層を作成する必要があります。プロトタイプがなければ、これはより面倒です。

ただし、特権メソッドを作成する場合は、コンストラクター自体にそれらをアタッチする必要があります。プロトタイプからこれを行うことはできません。例えば:

function Foo()
{
    var bar = 'baz';

    // privileged method
    this.bar = function() {
        return bar;
    }
}
var f = new Foo();
alert(f.bar()); // "baz"

私は過去 6 か月間この言語を使用しており、プロトタイプとコンストラクターを使用する状況は一度もなかったので、これを尋ねています。

new Option(...)またはnew XYZ()どこかを使用したことがある場合は、コンストラクターを使用しています。.hasOwnProperty()またはいつでも使用.toString()したことがある場合は、プロトタイプチェーンを使用していたでしょう:)

于 2013-08-27T05:43:28.743 に答える
2

プロトタイプは、通常、関数またはデフォルト値を定義する場所です。person オブジェクトと Person のメソッドを定義すると、Jon、Mike、および Betty インスタンスに対して同じgetNameことを行うと安全に言うことができます (それは を返します)。この関数は Person のすべてのインスタンスに対して同じことを行うため、 Person コンストラクタ本体で定義する必要はありません。getNamethis.namegetName

function Person(name){
  this.name = name; // This refers to the current instance
  this.getName = function(){
    return this.name;
  }
}
var Paul = new Person("Paul");// Paul has its own getName function
var Ben = new Person("Ben");// Ben has its own getName function
...

上記のコードでは、 Person はコンストラクターと呼ばれ、コンストラクターを呼び出すことで Person の新しいインスタンスを作成できますvar someone=new Person。今someoneは人のインスタンスです。上記のコードでは、すべてのインスタンスに独自の getName があることがわかります。オブジェクトに多くの関数があり、多くのインスタンスを作成している場合、インスタンスとメモリを作成するたびに関数を開始することで CPU 時間を浪費することになります (すべてのインスタンスには getName があるため)。他のすべてのインスタンスと同じことを行う一連の関数)。

上記で作成されたオブジェクト、Paul と Ben の場合、ステートメントPaul.hasOwnProperty('getName')は true になります。

getName を Person.prototype に配置すると、実際にはすべての Person インスタンスに対して getName 関数が 1 つだけになります。新しい Person インスタンスには Person.prototype を介して getName がありますが、Person を作成するたびに getName が初期化されるわけではありません。100 の Person インスタンスを作成してから Person.prototype.getName を変更すると、これらの作成されたすべてのインスタンスは、変更された getName 関数を使用します。

次に、考慮したい継承があります (JavaScript にはクラスがありません)。Person のこれらすべての共有メソッドを取得して、(たとえば) Employee のプロトタイプにコピーできます。getName は Person.prototype の関数であり、Emloyee がそれを継承しているため、直接呼び出すことができますemployeeInstance.getName()。Employee が getName で追加の作業を必要とする場合は、Person 関数をオーバーライドして呼び出すことができます (以下のコードを参照)。

Employee.prototype.getName=function(){
  return Person.getName.call(this) + " " + this.jobTitle;
}

コンストラクター関数、継承、オーバーライド関数の詳細については、この回答をご覧ください。

これらの単語が理解できない場合は、Java チュートリアルを読むことをお勧めします。これを行う理由を説明します。Java は技術的にはクラスを使用しますが、継承とオーバーライドとは何か、またそれを使用する理由について説明します。

OOP を 1 回の投稿で説明するのはちょっと難しいですが、上記のチュートリアルでその一部を説明します。Java は JavaScript ではなく、プライベート メンバー、型チェック、インターフェイスなどは JavaScript ではサポートされていません。一方、オブジェクトのインスタンスを変更したい場合は、JavaScript の方がはるかに柔軟です。

パターンを調べると、OOP の真の力が明らかになります。インターネット上には数え切れないほどの記事があるので、グーグルで検索できます。

于 2013-08-22T01:15:02.913 に答える