برنامهنویسی شئگرا - جاوااسکریپت: متد کلاس در مقابل متد prototype کلاس


تفاوت بین دو اعلان زیر چیست؟

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

آیا درست است که اولین عبارت را به عنوان اعلان یک متد ایستا در نظر بگیریم و دومین عبارت را به عنوان اعلان یک متد نمونه؟

پاسخ شماره ۱

بله، اولین تابع هیچ رابطهای با یک نمونه شیء از آن تابع سازنده ندارد، میتوانید آن را مانند یک «متد استاتیک» در نظر بگیرید.

در جاوااسکریپت توابع اشیاء اولین-رتبه هستند، به این معنی که میتوانید با آنها همانند هر شیء دیگری رفتار کنید، در این حالت، شما فقط یک ویژگی به شیء تابع اضافه میکنید.

تابع دوم، همانطور که پروتوتایپ تابع سازنده را گسترش میدهید، برای تمام نمونههای شیء ایجاد شده با کلیدواژه 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();

پاسخ شماره ۲

بله، اولی یک متد استاتیک است که همچنین متد کلاس نامیده میشود، در حالی که دومی یک متد نمونه است.

برای درک آن به طور دقیقتر، مثالهای زیر را در نظر بگیرید.

در 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"

توجه: هر دو مثال اساساً یکسان هستند، جاوااسکریپت همچنان یک زبان بدون کلاس باقی میماند. class معرفیشده در ES6 عمدتاً یک شیرینی نحوی بر روی مدل ارثبری مبتنی بر پروتوتایپ موجود است.

پاسخ شماره ۳

هنگامی که بیش از یک نمونه از MyClass ایجاد میکنید، هنوز تنها یک نمونه از publicMethod در حافظه خواهید داشت، اما در مورد privilegedMethod، در نهایت تعداد زیادی نمونه ایجاد خواهید کرد و staticMethod هیچ ارتباطی با یک نمونه از شیء ندارد.

به همین دلیل پروتوتایپها حافظه را ذخیره میکنند.

همچنین، اگر خصوصیات شیء والد را تغییر دهید، اگر خصوصیت مربوطهٔ فرزند تغییر نکرده باشد، بهروزرسانی خواهد شد.

پاسخ شماره ۴

برای یادگیرندگان بصری، هنگام تعریف تابع بدون .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() باعث خطا میشود و اجرای برنامه نمیتواند ادامه یابد.
اما برای اهداف توضیح و درک آسان، من این ترتیب را نگه داشتهام.****

نتایج تولید شده از کنسول توسعهدهنده کروم و JS Bin
برای قدمبهقدم بررسی کردن کد، روی لینک jsbin بالا کلیک کنید.
برای تغییر وضعیت بخش کامنتشده از ctrl+/ استفاده کنید