11

これが推奨される方法ではないことはわかっていますが、次の関数を宣言してからコンストラクターとして呼び出すと、結果のオブジェクトの違いは何になりますか?

function Something() {
    this.foo = "bar";
}

function something2() {
    var that = {};
    that.foo = "bar";
    return that;
}

var x = new Something();
var y = new something2();
var z = something2();

xつまり、yzここで何が違うのでしょうか?

使用するかどうかは関数の結果に影響を与えないsomething2ので、コンストラクターを作成するためのはるかに優れた方法ではないでしょうか。new

ところでsomething2、ここで大文字にする必要がありますか?(Crockfordはキャピタライゼーションに非常に固執しているので、関数がグローバル名前空間を壊してしまうためではないと思います...)

4

4 に答える 4

15

要するに:

new something2() instanceof something2 === false

関連して、プロトタイププロパティを使用するように例を拡張する場合

Something.prototype.method = function () { };
something2.prototype.method = function () { };

後者の場合、プロトタイプは継承されないことがわかります。

typeof (new Something()).method === "function"
type (new something2()).method === "undefined"

本当の答えは、まったく異なる基盤となる機械を利用しているということです。withをnew呼び出すと、[[Construct]]メカニズムが呼び出されます。このメカニズムでは、コンストラクターのプロパティに従って[[Prototype]]プロパティを設定し.prototypeます。

しかし、[[Construct]]アルゴリズムのステップ8〜10で面白いことが起こります。新しい空のオブジェクトを設定し、その[[Prototype]]をアタッチした後、実際のオブジェクトに[[Call]]を実行します。この新しいempty-plus-prototypeオブジェクトをとして使用するコンストラクターthis。そして、ステップ9で、そのコンストラクターが何かを返したことが判明した場合---thisセットアップにすべての時間を費やした、プロトタイプにバインドされた、オブジェクトとして渡されたオブジェクトを破棄します。

注:オブジェクトの[[Prototype]](コンストラクターの]とは異なります.prototype)には、次のコマンドでアクセスできますObject.getPrototypeOf

Object.getPrototypeOf(new Something()) === Something.prototype // steps 5 & 6
Object.getPrototypeOf(new something2()) === Object.prototype // default

いくつかのメタ質問に答えるには:

  • something2いいえ、これはファクトリー関数でありコンストラクターではないため、大文字にしないでください。何かが大文字になっている場合、コンストラクターのセマンティクスを持つことが期待されますnew A() instanceof A
  • グローバル名前空間を破壊する危険性が心配な場合は、ファイルの先頭に配置して、厳密モード"use strict";の使用を開始する必要があります。strictモードの多くの優れたクリーンアップの1つは、thisデフォルトundefinedでグローバルオブジェクトではなく、に設定されることです。たとえば、コンストラクターを指定せずにコンストラクターを呼び出すと、コンストラクターnewがプロパティをにアタッチしようとしたときにエラーが発生しundefinedます。
  • ファクトリ関数(別名「クロージャパターン」)は、次の場合に限り、一般にコンストラクタとクラスの合理的な代替手段です。(b)そのオブジェクトのインスタンスをあまり多く構築しない。後者は、クロージャパターンで、すべてのメソッドの新しいインスタンスをすべての新しく作成されたオブジェクトにアタッチするためです。これは、メモリ使用量には適していません。クロージャパターンの最大の見返りであるIMOは、「プライベート」変数を使用できることです(これは良いことであり、他の人に言わせないでください:P)。
于 2012-04-26T06:49:46.490 に答える
2

2番目のケースでは、返されたオブジェクトはコンストラクターから何も継承しないため、そのように使用する意味はほとんどありません。

> var x = new Something();
> var y = new something2();
> var z = something2();

つまり、ここでx、y、zの違いは何ですか?

xから継承します。Somethingどちらでもないyか、zから継承しsomething2ます。

newを使用するかどうかは関数の結果に影響しないため、something2はコンストラクターを作成するためのはるかに優れた方法ではないでしょうか。

コンストラクターとして呼び出す意味はありません。コンストラクターが返すオブジェクトは、から継承するsomething2オブジェクトに割り当てられた新しく構築されたオブジェクトではないためです。これは、他の人がを呼び出すときに取得することを期待する可能性があります。thissomething2.prototypenew something2()

ところで、something2はここで大文字にする必要がありますか?(Crockfordはキャピタライゼーションに非常に固執しているので、関数がグローバル名前空間を壊してしまうためではないと思います...)

いいえ、コンストラクターとして呼び出すのは少し無意味なので、1つとして特徴付けることは誤解を招く可能性があります。

于 2012-04-26T06:49:19.330 に答える
1

関数をコンストラクターとして(つまり、newを使用して)呼び出すとkeyword、次の手順が実行されます。

  1. 新しいオブジェクトを作成する
  2. そのオブジェクトのプロトタイプをprototype関数のプロパティのオブジェクトに設定します
  3. そのオブジェクトのコンテキストでコンストラクター関数を実行します(つまりthis、新しいオブジェクトです)
  4. そのオブジェクトを返します(コンストラクターにreturnステートメントがない場合)

したがって、2番目のソリューションは、プロパティ「foo」を持つプレーンオブジェクトを返すだけです。しかし、そのプロトタイプから継承することも、継承することyzありません。instanceof Something2そのような関数はありますが、コンストラクターと呼ばれるべきではありません(大文字の命名やでの呼び出しはありませんnew)。それらはファクトリパターンに属しています。

newなしで実行できるコンストラクターが必要な場合は、次のコードを使用します。

function Something(params) {
    if (! this instanceof Something)
         return new Something(params);
    // else use "this" as usual
    this.foo = "bar";
    ...
 }
于 2012-04-26T06:56:24.810 に答える
1

最も重要なことは、返されたオブジェクトのプロトタイプだと思います。

  function Something() {
       this.foo = "bar";
  }

  Something.prototype = {
    // Something prototype code
    hello: function(){
     //...
    }
  }

  function something2() {
     var that = {};
     that.foo = "bar";
     return that;
  }

  something2.prototype = {
      // something2 prototype code
      greetings : function() {
      //...
      }
  }

  var x = new Something();
  var y = new something2();
  var z = something2();

  typeof x.hello === function // should be true
  typeof y.greetings === undefined // should be true
  typeof z.greetings === undefined // should be true

つまり、何か2を使用してオブジェクトをインスタンス化するのではなく、Objectから継承する純粋に新しいオブジェクトを作成しているということです。

  1. newキーワードを使用すると、Something()は「Something」タイプの新しいオブジェクトを提供します。
  2. something2()は、「Object」タイプの新しいオブジェクトを提供します。これにより、新しい空のオブジェクトがすぐに返されます。
  3. 新しいsomething2は、新しいオブジェクトを作成する空白のスコープを作成しているため、非効率的です。

    var that = {};
    

    これは

    var that = new Object();
    
于 2012-04-26T07:00:38.123 に答える