JavaScript:Class.methodとClass.prototype.method


499

次の2つの宣言の違いは何ですか?

Class.method = function () { /* code */ }
Class.prototype.method = function () { /* code using this.values */ }

最初のステートメントを静的メソッドの宣言と考え、2番目のステートメントをインスタンスメソッドの宣言と考えても問題ありませんか?

回答:


696

はい、最初の関数はそのコンストラクター関数のオブジェクトインスタンスとは関係ありません。「静的メソッド」のように考えることができます。

JavaScriptでは、関数はファーストクラスのオブジェクトです。つまり、他のオブジェクトと同じように扱うことができます。この場合、関数オブジェクトにプロパティを追加するだけです。

2番目の関数は、コンストラクター関数プロトタイプを拡張しているため、newキーワードで作成されたすべてのオブジェクトインスタンスで使用でき、その関数内のコンテキスト(thisキーワード)は、それを呼び出す実際のオブジェクトインスタンスを参照します。

この例を考えてみましょう:

// constructor function
function MyClass () {
  var privateVariable; // private member only available within the constructor fn

  this.privilegedMethod = function () { // it can access private members
    //..
  };
}

// A 'static method', it's just like a normal function 
// it has no relation with any 'MyClass' object instance
MyClass.staticMethod = function () {};

MyClass.prototype.publicMethod = function () {
  // the 'this' keyword refers to the object instance
  // you can access only 'privileged' and 'public' members
};

var myObj = new MyClass(); // new object instance

myObj.publicMethod();
MyClass.staticMethod();

1
しかし、なぜFunction.prototype.method == Function.methodなのでしょうか?
Raghavendra

1
@Raghavendraありません
Zorgatone 2017年

1
@メンダあなたのリンクは死んでいます
Eugen Sunic

19

MyClassの複数のインスタンスを作成しても、メモリにはpublicMethodのインスタンスが1つしかありませんが、privilegedMethodの場合、多くのインスタンスが作成され、staticMethodはオブジェクトインスタンスと関係がありません。

これが、プロトタイプがメモリを節約する理由です。

また、親オブジェクトのプロパティを変更した場合、子の対応するプロパティが変更されていない場合は、更新されます。


15

視覚的な学習者の場合、関数を定義せずに .prototype

ExampleClass = function(){};
ExampleClass.method = function(customString){
             console.log((customString !== undefined)? 
                          customString : 
                          "called from func def.");}
ExampleClass.method(); // >> output: `called from func def.`  

var someInstance = new ExampleClass();
someInstance.method('Called from instance');
    // >> error! `someInstance.method is not a function`  

同じコードで、.prototype追加された場合、

ExampleClass.prototype.method = function(customString){
             console.log((customString !== undefined)? 
                          customString : 
                          "called from func def.");}
ExampleClass.method();  
      // > error! `ExampleClass.method is not a function.`  

var someInstance = new ExampleClass();
someInstance.method('Called from instance');
                 // > output: `Called from instance`

より明確にするために

ExampleClass = function(){};
ExampleClass.directM = function(){}  //M for method
ExampleClass.prototype.protoM = function(){}

var instanceOfExample = new ExampleClass();

ExampleClass.directM();      works
instanceOfExample.directM();   x Error!

ExampleClass.protoM();     x Error!
instanceOfExample.protoM();   works

****上記の例では、someInstance.method()は実行されません。ExampleClass.method()が
原因でエラーが発生し、実行を続行できません。
ただし、説明と理解を容易にするために、この順序を維持しました。****

生成された結果chrome developer console& 上記のjsbinリンクをクリックして、コードをステップ実行します。+で コメントセクションを切り替えJS Bin

ctrl/


15

はい、1つ目はとstatic methodも呼ばれclass method、2つ目はinstance methodます。

より詳細に理解するために、以下の例を検討してください。

ES5内

function Person(firstName, lastName) {
   this.firstName = firstName;
   this.lastName = lastName;
}

Person.isPerson = function(obj) {
   return obj.constructor === Person;
}

Person.prototype.sayHi = function() {
   return "Hi " + this.firstName;
}

上記のコードでisPersonは、は静的メソッドsayHiですが、のインスタンスメソッドですPerson

以下は、Personコンストラクタからオブジェクトを作成する方法です。

var aminu = new Person("Aminu", "Abubakar");

静的メソッドを使用しますisPerson

Person.isPerson(aminu); // will return true

インスタンスメソッドを使用しますsayHi

aminu.sayHi(); // will return "Hi Aminu"

ES6内

class Person {
   constructor(firstName, lastName) {
      this.firstName = firstName;
      this.lastName = lastName;
   }

   static isPerson(obj) {
      return obj.constructor === Person;
   }

   sayHi() {
      return `Hi ${this.firstName}`;
   }
}

static静的メソッドを宣言するためにキーワードがどのように使用されたかを見てくださいisPerson

Personクラスのオブジェクトを作成します。

const aminu = new Person("Aminu", "Abubakar");

静的メソッドを使用しますisPerson

Person.isPerson(aminu); // will return true

インスタンスメソッドを使用しますsayHi

aminu.sayHi(); // will return "Hi Aminu"

注:どちらの例も基本的に同じですが、JavaScriptはクラスレス言語のままです。classで導入されたES6は、主に既存のプロトタイプベースの継承モデルを超える構文糖です。


「In ES6」では、シンタックスシュガーのみを記述します。これは「ES2015」ではありません(ES6の使用を中止し、適切な用語ES2015を使用しないでください)。これは単に別の方法であり、私の意見では間違った方法です。
K-SOの毒性が高まっています。

2
@KarlMorrison Aminuは「それを行う方法」を書きませんでした。あなたは自分でそれを書き、例外を取りました。ES6とES2015については公平かもしれませんが、会話では効率を上げるために短い規約に頼ることが多いため、執筆から削除することは不可能であるか、確実に推奨されます。
ウリウォン

回答のES6部分をありがとうございます。特に、上記の2つの「公開+特権」の回答と組み合わせると、多くのことが明確になります。しかし、私はあなたの模範であることに完全に混乱してobj.constructor === Persontrueます... クラスインスタンスのコンストラクタ===はどのようにしてクラス自体を...できますか?(これは、セットのサブセットがセット自体であると言っているようなものです...)
Andrew

ああ...これで言いたいことは、文字通り、コンストラクターはJSクラスが本当に1日の終わりに持っていることだけですか?他のすべては、名前/コンセプト(および暗黙の「this」が明らかに利用できるようになることを除いて)を除いて、コンストラクタに完全に積み重ねられるか、または完全にクラスから分離された静的コンストラクトのいずれかです。(したがって、私がセットのサブセットであると思っていたものは、実際にはサブセットではありませんでした。)
Andrew
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.