2012-04-26 8 views
10

私はこれをお勧めする方法ではないことを知っていますが、次の関数を宣言してコンストラクタとして呼び出すと、結果のオブジェクトの違いは何ですか?コンストラクタ関数と、コンストラクタとして呼び出されるオブジェクトを返す関数との間にJavaScriptの違いはありますか?

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(); 

e.e.e. xyzの違いは何ですか?

newを使用するかどうかは関数の結果に影響しないので、something2はコンストラクタを書くよりはるかに良い方法でしょうか?

本書は、something2をここで大文字で入力してください。 (私は、Crockfordが大文字に大変忠実であるので、関数はグローバル名前空間を壊すので...)

+2

に相当し、新しいオブジェクト

var that = {}; 

氏の少し警戒して作成し、そこから空白の範囲を、作成しているため、新しいsomething2は、非効率的ですクロフォード。彼には良いことがたくさんありますが、意見には意見があります。 – staticsan

答えて

14

関連し
new something2() instanceof something2 === false 

、あなたはprototypeプロパティ

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

を使用するためにあなたの例を拡張する場合は、プロトタイプが後者の場合には継承されていないことがわかります:

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

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

しかし、[[Construct]]アルゴリズムのステップ8-10では、新しい空のオブジェクトを設定してから、[[Prototype]]を付けた後、[[Call] ]を実際のコンストラクタに渡します。この新しい空白+プロトタイプオブジェクトはthisです。そして、ステップ9で、そのコンストラクタが何かを返すことが判明した場合、それはそのプロトタイプバインドされたものをスローして、そのまま渡します。this

注:いくつかのメタの質問に答えるために

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

:あなたはObject.getPrototypeOfと、オブジェクトの[[プロトタイプ]]を(コンストラクタの.prototypeは異なる)にアクセスすることができます

  • いいえ、something2はファクトリ関数であり、コンストラクタではないため、大文字ではありません。何かが大文字にされていると、コンストラクタセマンティクスを持つことが期待されます。 new A() instanceof A
  • グローバル名前空間が壊れる危険性がある場合は、ファイルの先頭に"use strict";と入力してstrict modeを使用してください。厳密モードの多くの素敵なクリーンアップの1つは、thisがデフォルトでundefinedであり、グローバルオブジェクトではないということです。 newを含まないコンストラクタを呼び出すと、コンストラクタがプロパティをundefinedにアタッチしようとするとエラーが発生します。
  • ファクトリ関数(「クロージャパターン」とも呼ばれます)は、(a)継承を使用しない限り、一般的にコンストラクタとクラスの代用として適しています。 (b)そのオブジェクトのインスタンスをあまりにも多く構築していない。後者の理由は、クロージャーパターンでは、すべてのメソッドの新しいインスタンスを新しく作成されたすべてのオブジェクトにアタッチするためです。これはメモリ使用にはあまり役に立ちません。クロージャパターンの最大の利益(IMO)は、"private" variables(これはgood thingであり、他に誰かにあなたに伝えさせないでください:P)を使う能力です。 (新しいkeywordとIE)コンストラクタとしての機能を呼び出す
+0

2番目の方法では 'new'もオプションです(または実際には必要ありません)。最初の部分(この===ウィンドウ)に残しておくとネジが入ります – Matt

+0

@ Matt-内部から少し防御できます'this'がグローバルオブジェクトであるかどうかを確認し、それに応じて処理を行います。 – RobG

+1

@Matt、@RobG ---ファイルの先頭に厳密な ";"を入れてください!それで 'これは'未定義です。 – Domenic

2

2番目のケースでは、返されたオブジェクトはコンストラクタから何も継承しないので、そのように使用します。

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

すなわち、 x、y、zの違いは? Something、どちらのwheres yまたはsomething2からz継承から

x継承。新しいを使用するかどうか 関数の結果には影響しませんので、

はsomething2は、コンストラクタ、 を書くより良い方法ではないでしょうか?

new something2()を呼び出すときに取得するために期待するかもしれない何か他のものであるが返すオブジェクトがsomething2.prototypeから継承しthisに割り当て新しく構築されたオブジェクトではありませんので、コンストラクタとしてsomething2を呼び出すにはポイントはありません。

ここで大文字にする必要がありますか?コンストラクタとして呼び出すことは少し無意味ですので、ノー

( クロックフォードが総額にそう断固ているので、私は... グローバル名前空間を壊します機能のために、ではないと仮定)が1として、それを特徴づけます誤解を招く恐れがあります。要するに

1

次の手順を実行します:

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

したがって、2番目のソリューションでは、プロパティ "foo"を持つ単純なオブジェクトが返されます。しかし、yzinstanceof Something2であり、そのプロトタイプを継承していません。そのような機能はありますが、コンストラクタ(大文字のネーミングはありません。newの呼び出しは不要です)と呼ばれるべきではありません。それらは工場パターンに属します。

新しいなく実行できるコンストラクタは、そのコードを使用する場合:

function Something(params) { 
    if (! this instanceof Something) 
     return new Something(params); 
    // else use "this" as usual 
    this.foo = "bar"; 
    ... 
} 
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 

つまり、私はあなたが何かをインスタンス化していないと言っています。オブジェクトから継承する純粋に新しいオブジェクトを作成しています。

  1. あなたは新しいキーワードを使用するときに()何かがあなたに「何か」タイプの新しいオブジェクトを提供します。
  2. something2()は、新しい空オブジェクトをただちに返す "Object"型の新しいオブジェクトを提供します。
  3. あなたが

    var that = new Object(); 
    
関連する問題