2016-11-02 35 views
3

JavaScriptは、クラスのようなオブジェクトのメソッドまたはプロパティを定義する方法としてObject.prototypeを定義します。Object.prototype/JavaScriptインスタンスメソッドを使用する場合

Object.prototypeを使用する方法は、呼び出し元のコンテキストを持つことになりますthisとしてコールバックを経由して呼び出される 間違った 行動があるときに存在する大きな問題。

function Foo() {} 

Foo.prototype.resize() { 
    console.log(this); 
} 

var foo = new Foo(); 
window.on('resize', foo.resize); 

この制限を回避するために、以下のことができます。このような状況を考えると

function Foo2() { 
    function resize() { 
    console.log(self); 
    } 

    var self = this; 
    this.resize = resize; 
} 

var foo2 = new Foo2(); 
window.on('resize', foo2.resize); 

我々はObject.prototype施設を使用する必要があるとき、それはにましだように思える常には、このように例では2

をクラスのようなオブジェクトを定義しますか?つまり、あなたのメソッドがどのように呼び出されるかを先験的に知ることはできません。そして、呼び出されたときにコンテキストの参照が正しいことが最も確実です。

サポート状況:あなたはObject.prototypeを使用して、インスタンス・メソッドを作成しているようにそれはそうと、私はこの質問を考えました。しかし、図示のとおり、あなたはそうではありません。インスタンスへの「実際の」接続がないメソッドを作成するだけです。したがって、インスタンスにバインドされたメソッドを作成するためにクロージャを使用する必要があります。さらに、この質問はthis excellent explanation of thisを読んだ後に考えられた。

+4

は、あなただけの 'window.on( 'リサイズ'、foo.resize.bind(FOO))をしないだろう;' ?それが起こっている理由は、 'this'は実行コンテキストに完全に依存し、イベントハンドラではその関数が参照され、ハンドラによって呼び出されるからです。 – adeneo

+0

あなたは 'this'の使用を完全に禁じることができます... – evolutionxbox

+1

プロトタイプの最大の利点はメモリ節約です。特定のタイプのインスタンスを100万個作成することができます。プロトタイプを使用する場合は、各関数のコピーは1つのみです。クロージャーアプローチを使用すると、すべての機能のわずかに異なるコピーが作成されます。私がJavaScriptで定義するオブジェクトは、 'this 'が引き起こすすべての混乱とバグのためにプロトタイプや' this'を使用しませんが、プロトタイプのメモリ節約の利点を否定することはできません。 – JLRishe

答えて

3

あなたの混乱は、JavaScriptオブジェクトをOOP言語のようなメソッドを持つものとして見るという事実から来ています。 OOP言語のメソッドは通常「初期バインディング」を使用しているため、正しいコンテキストにバインドされているため、コンテキストを固定する必要があると考えています。それはJavaScriptで異なっています。関数の実行時に、関数のコンテキスト(this)が決定されたときに、「遅延結合」のようなものです。私にとっては、メソッドを単に関数を指すオブジェクトのプロパティとして見て、実際には異なるコンテキストで実行できることが有益です。必要であれば、確かにあなたが例えばbindを使用して「早期バインディング」を達成することができます

function resize() { 
    console.log(this); 
} 

resize.call(window); 
resize.call(custom); 

:たとえば、私たちはこのような何かを持っている可能性が

function O() { 
     this.resize = function() {}.bind(this); 
    } 

    var o = new O(); 

しかし、オブジェクトの限界が再ユーザビリティいますメソッド。たとえば、これは不可能であろう。

Array.prototype.slice.call(arguments) 

あなたは方法がさえES6に拘束されていない理由について、いくつかの提案をhereを読むことができます。

プロトタイプは、それらが、メモリ効率的なコードの再利用を可能にするために作成され、static methodsではありません。JLRisheが指摘したように、あなたがプロトタイプの機能の1つのインスタンスを定義し、そのプロトタイプチェーン内のプロトタイプを持つオブジェクトのプロパティとしてそれに便利アクセスすることができるため、プロトタイプの最大の利点は、メモリ使用量の削減です。しかし、プロトタイプは便宜上のものです。ここでprototypeなしresizeと例です:あなたは、単に そのインスタンスへの「本当の」接続されていないメソッドを作成している

// here only one instance of `resize` function is created 
function resize() { 
    console.log(this); 
} 

var o1 = { 
    resize: resize 
} 

var o2 = { 
    resize: resize 
} 

正しいが、ここでは、後に別のコンテキストで使用する「メソッド」とプロトタイプの例である:

var prototype = { 
    resize: function() { 
    console.log(this); 
    } 
} 

var o1 = { 
    resize: resize 
} 

Object.setPrototypeOf(o1, prototype); 

var o2 = { 
    resize: resize 
} 

Object.setPrototypeOf(o2, prototype); 

私はJavaScriptは関数がファーストクラスのオブジェクトであることを念頭に置いて考えに建てられたと思いますそのオブジェクトは、正しくバインドされたコンテキストを持つメソッドを持つべきではありません。

静的メソッドは、通常はこのように、関数コンストラクタのプロパティとして実装されています:

function SomeObjectConstructor() {} 
SomeObjectConstructor.someStaticMethod = function() {} 
+0

間違いなく私は私の記事にリンクしている答えを読む前にいくつかの混乱。 OOPの観点から、 'Object.prototype'は' static methods'の定義に似ています。静的メソッドは間違いなく便利ですが、コンテキストを正しく取得するにはいくつかのアクロバットを実行する必要があります。 JavaScriptにはインスタンスを取得する方法が含まれていないことが奇妙に思えます(アクロバット以外* * bind *、* closure *など)。 – James

+1

いいえ、 'prototype'はコードを再利用する方法です。私の答えの最後の部分を確認してください。静的メソッドは、多くの場合、関数コンストラクターのプロパティとして実装されます。私はこれを答えに加えてみましょう –

+0

@JLRishe、ええ、ありがとう、更新されました –

1

私は直接イベントハンドラに、オブジェクトのメソッドを結合することを考えて、可能ではあるが、あなたは避けたいショートカットです。

window.on('resize', function() { 
    foo.resize(); 
}); 

それはより冗長だにもかかわらず、私はこのようなあなたのハンドラを書くことは明確であり、あなたのObject.prototype方法でthisの状況に影響を与える文句を言わないと思います。

コメントの1で述べたように、オブジェクトのプロトタイプを使用すると、あなたのオブジェクトの各インスタンスのメソッドを定義するよりも効率的です。

関連する問題