JavaScript: Class.method so với Class.prototype.method


499

Sự khác biệt giữa hai tuyên bố sau là gì?

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

Có thể nghĩ rằng câu lệnh đầu tiên là một tuyên bố của một phương thức tĩnh và câu lệnh thứ hai là một tuyên bố của một phương thức cá thể không?

Câu trả lời:


696

Đúng, hàm đầu tiên không có mối quan hệ với một đối tượng của hàm xây dựng đó , bạn có thể coi nó như một 'phương thức tĩnh' .

Trong các hàm JavaScript là các đối tượng hạng nhất , điều đó có nghĩa là bạn có thể đối xử với chúng giống như bất kỳ đối tượng nào, trong trường hợp này, bạn chỉ thêm một thuộc tính vào đối tượng hàm .

Hàm thứ hai, khi bạn mở rộng nguyên mẫu hàm xây dựng, nó sẽ có sẵn cho tất cả các thể hiện đối tượng được tạo bằng newtừ khóa và ngữ cảnh trong hàm đó ( thistừ khóa) sẽ tham chiếu đến thể hiện đối tượng thực tế nơi bạn gọi nó.

Xem xét ví dụ này:

// 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
Nhưng tại sao Function.prototype.method == Function.method?
Raghavendra

1
@Raghavendra không phải thế
Zorgatone

1
@ Chương trình liên kết của bạn đã chết
Eugen Sunic

19

Khi bạn tạo nhiều hơn một phiên bản MyClass, bạn sẽ vẫn chỉ có một phiên bản publicMethod trong bộ nhớ nhưng trong trường hợp đặc quyềnMethod, bạn sẽ tạo ra rất nhiều phiên bản và staticMethod không có mối quan hệ nào với một thể hiện đối tượng.

Đó là lý do tại sao các nguyên mẫu tiết kiệm bộ nhớ.

Ngoài ra, nếu bạn thay đổi thuộc tính của đối tượng cha, là thuộc tính tương ứng của con chưa được thay đổi, nó sẽ được cập nhật.


15

Đối với người học trực quan, khi xác định hàm không có .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`  

Với cùng một mã, nếu .prototypeđược thêm vào,

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`

Để làm cho nó rõ ràng hơn,

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

**** Lưu ý cho ví dụ ở trên, someInstance.method () sẽ không được thực thi vì,
exampleClass.method () gây ra lỗi và việc thực thi không thể tiếp tục.
Nhưng để minh họa và dễ hiểu, tôi đã giữ trình tự này. ****

Kết quả được tạo từ chrome developer console& Nhấp vào liên kết jsbin ở trên để chuyển qua mã. Chuyển đổi phần bình luận với +JS Bin

ctrl/


15

Vâng, cái đầu tiên là một static methodcũng được gọi class method, trong khi cái thứ hai là một instance method.

Hãy xem xét các ví dụ sau đây, để hiểu nó chi tiết hơn.

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

Trong đoạn mã trên, isPersonlà một phương thức tĩnh, trong khi sayHilà một phương thức thể hiện của Person.

Dưới đây, là cách tạo một đối tượng từ Personconstructor.

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

Sử dụng phương pháp tĩnh isPerson.

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

Sử dụng phương thức ví dụ sayHi.

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

Trong ES6

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

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

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

Nhìn vào cách statictừ khóa được sử dụng để khai báo phương thức tĩnh isPerson.

Để tạo một đối tượng của Personlớp.

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

Sử dụng phương pháp tĩnh isPerson.

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

Sử dụng phương thức ví dụ sayHi.

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

LƯU Ý: Cả hai ví dụ về cơ bản là giống nhau, JavaScript vẫn là ngôn ngữ không có lớp. Các classgiới thiệu trong ES6 chủ yếu là một đường cú pháp trên mô hình thừa kế dựa trên nguyên mẫu hiện có.


"Trong ES6" bạn chỉ mô tả một cú pháp đường. Đây không phải là "ES2015" (vui lòng mọi người ngừng sử dụng ES6 sử dụng thuật ngữ ES2015 thích hợp) để thực hiện. Nó chỉ đơn giản là một cách khác để làm điều đó và theo tôi là cách không chính xác.
K - Độc tính trong SO đang tăng lên.

2
@KarlMorrison Aminu không viết "cách làm" mà bạn chỉ tự viết và ngoại lệ với nó. Quan điểm của bạn có thể công bằng về ES6 so với ES2015 nhưng trong cuộc trò chuyện, mọi người thường sử dụng một quy ước ngắn hơn để đạt hiệu quả, vì vậy tôi nghĩ loại bỏ nó khỏi văn bản là không thể hoặc chắc chắn là có thể khuyên được.
wuliwong

Cảm ơn bạn về phần ES6 trong câu trả lời của bạn; điều đó làm rõ rất nhiều, đặc biệt là khi kết hợp với 2 câu trả lời "công khai + đặc quyền" ở trên. Tuy nhiên tôi hoàn toàn nhầm lẫn bởi bạn obj.constructor === Personhạnh phúc truedụ mặc dù ... Whaaaat? Làm thế nào có thể xây dựng một cá thể ===lớp của chính lớp ...? (Giống như nói một tập hợp con của tập hợp là tập hợp chính nó, v.v ...)
Andrew

Ohhh ... đây có phải là tất cả để nói rằng theo nghĩa đen, hàm tạo là tất cả những gì một lớp JS thực sự ở cuối ngày không? Mọi thứ khác được chồng chất vào hàm tạo hoặc hoàn toàn là một cấu trúc tĩnh được phân lập từ lớp ngoại trừ theo tên / khái niệm (và giống như một "điều này" ngụ ý rõ ràng)? (Vì vậy, những gì tôi nghĩ là một tập hợp con của tập hợp thực sự không phải là một tập hợp con.)
Andrew
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.