JavaScript: Class.method vs. Class.prototype.method

499

Apa perbedaan antara dua deklarasi berikut?

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

Apakah saya tetap bisa menganggap pernyataan pertama sebagai deklarasi metode statis, dan pernyataan kedua sebagai deklarasi metode instance?

postrasional
sumber

Jawaban:

696

Ya, fungsi pertama tidak memiliki hubungan dengan instance objek dari fungsi konstruktor itu , Anda dapat menganggapnya sebagai 'metode statis' .

Dalam fungsi JavaScript adalah objek kelas satu , yang berarti Anda dapat memperlakukannya sama seperti objek apa pun, dalam hal ini, Anda hanya menambahkan properti ke objek fungsi .

Fungsi kedua, saat Anda memperluas prototipe fungsi konstruktor, itu akan tersedia untuk semua instance objek yang dibuat dengan newkata kunci, dan konteks di dalam fungsi tersebut ( thiskata kunci) akan merujuk ke instance objek aktual di mana Anda menyebutnya.

Pertimbangkan contoh ini:

// 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();
CMS
sumber
1
Tetapi mengapa Function.prototype.method == Function.method?
Raghavendra
1
@Raghavendra bukan
Zorgatone
1
@Rencanakan tautan Anda sudah mati
Eugen Sunic
19

Ketika Anda membuat lebih dari satu instance dari MyClass, Anda hanya akan memiliki hanya satu instance publicMethod dalam memori tetapi dalam kasus privilegeMethod Anda akhirnya akan membuat banyak instance dan staticMethod tidak memiliki hubungan dengan instance objek.

Itu sebabnya prototipe menghemat memori.

Juga, jika Anda mengubah properti objek induk, apakah properti yang sesuai anak itu belum diubah, itu akan diperbarui.

pengguna2440156
sumber
15

Untuk pelajar visual, ketika mendefinisikan fungsi tanpa .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`  

Dengan kode yang sama, jika .prototypeditambahkan,

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`

Untuk membuatnya lebih jelas,

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

**** Catatan untuk contoh di atas, someInstance.method () tidak akan dieksekusi karena,
ExampleClass.method () menyebabkan kesalahan & eksekusi tidak dapat dilanjutkan.
Tetapi demi ilustrasi & pemahaman yang mudah, saya telah menjaga urutan ini. ****

Hasil yang dihasilkan dari chrome developer console& Klik tautan jsbin di atas untuk melangkah melalui kode. Toggle bagian komentar dengan +JS Bin

ctrl/

SAm
sumber
15

Ya, yang pertama static methoddisebut juga class method, sedangkan yang kedua adalah instance method.

Perhatikan contoh-contoh berikut, untuk memahaminya secara lebih rinci.

Dalam 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;
}

Dalam kode di atas, isPersonadalah metode statis, sedangkan sayHimetode instan dari Person.

Di bawah ini adalah cara membuat objek dari Personkonstruktor.

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

Menggunakan metode statis isPerson.

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

Menggunakan metode instance sayHi.

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

Dalam ES6

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

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

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

Lihat bagaimana statickata kunci digunakan untuk mendeklarasikan metode statis isPerson.

Untuk membuat objek Personkelas.

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

Menggunakan metode statis isPerson.

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

Menggunakan metode instance sayHi.

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

CATATAN: Kedua contoh pada dasarnya sama, JavaScript tetap merupakan bahasa tanpa kelas. Yang classdiperkenalkan dalam ES6 terutama adalah gula sintaksis atas model pewarisan berbasis prototipe yang ada.

Aminu Kano
sumber
"Dalam ES6" Anda hanya menggambarkan gula sintaks. Ini bukan cara "ES2015" (tolong semua orang berhenti menggunakan ES6 menggunakan istilah ES2015 yang tepat) untuk melakukannya. Ini hanyalah cara lain untuk melakukannya dan menurut saya cara yang salah.
K - Keracunan dalam SO tumbuh.
2
@KarlMorrison Aminu tidak menulis "cara melakukannya", Anda hanya menulis sendiri dan mengambil pengecualian untuk itu. Maksud Anda mungkin adil tentang ES6 vs ES2015 tetapi dalam percakapan orang sering menggunakan konvensi yang lebih pendek untuk efisiensi, jadi saya pikir menghapusnya dari menulis tidak mungkin atau pasti disarankan.
wuliwong
Terima kasih atas bagian ES6 dari jawaban Anda; yang banyak mengklarifikasi, terutama bila dikombinasikan dengan 2 jawaban "publik + istimewa" di atas. Namun saya benar - benar bingung dengan obj.constructor === Personmenjadi truecontoh Anda ... Whaaaat? Bagaimana konstruktor instance ===kelas dengan kelas itu sendiri ...? (Itu seperti mengatakan subset dari himpunan adalah himpunan itu sendiri, dll ...)
Andrew
Ohhh ... apakah ini semua yang dapat dikatakan bahwa secara literal, konstruktor adalah semua yang benar-benar dimiliki oleh kelas JS pada akhirnya? Segala sesuatu yang lain baik ditumpuk ke dalam konstruktor atau benar-benar sebuah konstruksi statis yang terisolasi dari kelas kecuali dengan nama / konsep (dan seperti tersirat "ini" yang tersedia jelas)? (Jadi, yang saya pikir adalah himpunan bagian dari himpunan sebenarnya bukan himpunan bagian.)
Andrew