آموزش جاوا اسکریپت Java Script قسمت یازدهم

1395/4/17 اکرم کریمی 1652

بسم الله الرحمن الرحیم

با سلام خدمت همه همراهان گرامی، با جلسه یازدهم جاوااسکریپت در خدمت شما هستم.

در این جلسه به توضیح نمونه کدی که در جلسه قبل گذاشته بودم میپردازیم.

function Rectangle(x,y){
            this.x = x;
            this.y = y; 
            this.toString = function(){
                return "x: " + x + ", y: " + y;
   };
        }
        // Define a function in prototype.
        // Child objects will inherit it.
        Rectangle.prototype.area = function(){
            return this.x * this.y;
}
        function Square(x){
            Rectangle.call(this,x,x);// Call parent constructor with context switch.
        }
       Square.prototype.perimeter = function(){
            return this.x * 4;
        }
        var mySquare = new Square(3);
        mySquare.area(); // Returns 9

        (mySquare instanceof Square); // returns true
        (mySquare instanceof Rectangle); // returns true

ما یک کلاس یا تابع سازنده با نام Rectangle داریم که دارای دو پراپرتی x و y است، که این تابع سازنده مقادیر آنها رو از ورودی دریافت میکنه و به این پراپرتی ها انتساب میده. در ادامه این کد در پروتوتایپ تابع سازنده Rectangle یک تابع با نام area تعریف کردیم، برای اینکه نشون بدیم این این تابع به اشیاء فرزند این کلاس هم به ارث میرسه. (در ادامه بیشتر توضیح میدم)

خب، یه تابع سازنده دیگه با نام Square ایجاد میکنیم که در این تابع، سازنده والد اون یعنی Rectangle رو صدا میزنیم و به اون context جاری رو با استفاده از this پاس میدهیم. برای هر دو ورودی x و y هم مقدار آرگومان ورودی تابع Square، x رو در نظر گرفتیم. (چون در مربع طول و عرض با هم برابرند) این اولین قدم برای ایجاد ارث بری بین دو تابع سازنده یا به اصطلاح کلاسمون هست. خب، اینجا من فقط تابع سازنده والد رو صدا زدم و تا اینجا فقط توابعی که به صورت مستقیم درون خود تابع سازنده مون ایجاد شده بودند مثل toString رو میتونیم بهش دسترسی داشته باشیم و به فرزند به ارث میرسه، اما تابع area که بعد از آن به پروتوتایپ کلاس Rectangle اضافه شده به شئ ایجاد شده از کلاس  Square به ارث نمیرسد.

آموزش قسمت یازدهم جاوا اسکریپت Java Script

همانطور که در سمت راست شکل میبینید من شئ ایجاد شده رو به watch اضافه کردم و توابعی که توسط این شئ من به آنها دسترسی دارم فقط شامل toString است که در خود کلاس تعریف کرده بودم، و تابع area به این شئ به ارث نرسیده است. همونطور که میبینید من عملیات پردازش این کد رو بر سر خطی که تابع area رو فراخوانی میکرد متوقف کردم،چون این تابع به این شئ به ارث نرسیده و من در این خط به خطا خواهم خورد. دکمه F10 رو که بزنید این خطا رو خواهید دید. (خطاهای رخ داده درون کد رو میتونید در تب console ببینید)

من دو عبارت دیگه هم به watch اضافه کردم، mySquare instanceof Square که با برگرداندن مقدار true به ما میگه که این شئ یک نمونه از کلاس Square است همینطور mySquare instanceof Rectangle که با برگرداندن مقدار false به ما میگه که این شئ یک نمونه از کلاس Rectangle نیست!!! و در صورتی که ارث بری ما درست باشه این عبارت باید به ما مقدار true رو برگردونه! پس شئ ما باید نمونه ای از کلاس Rectangle هم باشه.

برای برطرف کردن این مشکل، کدم رو به صورت زیر تغییر میدم:

function Rectangle(x,y){ 
            this.x = x;
            this.y = y;
            
            this.toString = function() {
                return "x: " + x + ", y: " + y;
            };
        }
        // Define a function in prototype.
        // Child objects will inherit it.
        Rectangle.prototype.area = function(){
            return this.x * this.y;
        }
        function Square(x){
            Rectangle.call(this,x,x);// Call parent constructor with context switch.
        }

        Square.prototype = new Rectangle(); // Chain Square prototype to Rectangle

        Square.prototype.constructor = Square; // Define constructor for this prototype

        Square.prototype.perimeter = function(){
            return this.x * 4;
        }

        var mySquare = new Square(3);
        mySquare.area(); // Returns 9

        (mySquare instanceof Square); // returns true
        (mySquare instanceof Rectangle); // returns true

خب من خط کدهام رو یکی یکی جلو رفتم تا برسم بعد از اینکه شئ ام رو از کلاس Square ایجاد کردم،در اینجا ما باز هم تابع area رو به صورت مستقیم درون شئ نمی بینیم. ما برای برطرف کردن مشکل اینکه به تابع area دسترسی نداشتیم کاری که انجام دادیم این بود که یک شئ از کلاس Rectangle ایجاد کردیم و به prototype کلاس Square انتساب دادیم. اگر خاطرتون باشه جلسه قبل هم گفتیم که در ارث بری در جاوااسکریپت، پروتوتایپ یک شئ مشخص کننده کلاسیه که کلاس ایجاد کننده شئ مورد نظر از اون به ارث رسیده است. برای همین من برای مشخص کردن اینکه کلاس Square از کلاس Rectangle ارث بری کرده نیاز به این دارم که یک شئ از کلاس Rectangle به پروتوتایپ کلاس Square نسبت بدم تا این زنجیره پروتوتایپ هامون حفظ شه! گفته بودیم هم که آخرین حلقه این زنجیره کلاس Object است.

 Java Script آموزش قسمت یازدهم جاوا اسکریپت

همانطور که در سمت راست شکل میبینید من شئ ایجاد شده رو به watch اضافه کردم و توابعی که توسط این شئ من به آنها دسترسی دارم فقط شامل toString است که در خود کلاس تعریف کرده بودم، و تابع area به این شئ به ارث نرسیده است. همونطور که میبینید من عملیات پردازش این کد رو بر سر خطی که تابع area رو فراخوانی میکرد متوقف کردم،چون این تابع به این شئ به ارث نرسیده و من در این خط به خطا خواهم خورد. دکمه F10 رو که بزنید این خطا رو خواهید دید. (خطاهای رخ داده درون کد رو میتونید در تب console ببینید)

من دو عبارت دیگه هم به watch اضافه کردم، mySquare instanceof Square که با برگرداندن مقدار true به ما میگه که این شئ یک نمونه از کلاس Square است همینطور mySquare instanceof Rectangle که با برگرداندن مقدار false به ما میگه که این شئ یک نمونه از کلاس Rectangle نیست!!! و در صورتی که ارث بری ما درست باشه این عبارت باید به ما مقدار true رو برگردونه! پس شئ ما باید نمونه ای از کلاس Rectangle هم باشه.

برای برطرف کردن این مشکل، کدم رو به صورت زیر تغییر میدم:

function Rectangle(x,y){ 
            this.x = x;
            this.y = y;
            
            this.toString = function(){
                return "x: " + x + ", y: " + y;
            };
}
        // Define a function in prototype.
        // Child objects will inherit it.
        Rectangle.prototype.area = function(){
            return this.x * this.y;
        }

        function Square(x){
            Rectangle.call(this,x,x);// Call parent constructor with context switch.
        }	

        Square.prototype = new Rectangle(); // Chain Square prototype to Rectangle

        Square.prototype.constructor = Square; // Define constructor for this prototype

        Square.prototype.perimeter = function(){
            return this.x * 4;
        }

        var mySquare = new Square(3);
        mySquare.area(); // Returns 9
        (mySquare instanceof Square); // returns true
        (mySquare instanceof Rectangle); // returns true

خب من خط کدهام رو یکی یکی جلو رفتم تا برسم بعد از اینکه شئ ام رو از کلاس Square ایجاد کردم،در اینجا ما باز هم تابع area رو به صورت مستقیم درون شئ نمی بینیم. ما برای برطرف کردن مشکل اینکه به تابع area دسترسی نداشتیم کاری که انجام دادیم این بود که یک شئ از کلاس Rectangle ایجاد کردیم و به prototype کلاس Square انتساب دادیم. اگر خاطرتون باشه جلسه قبل هم گفتیم که در ارث بری در جاوااسکریپت، پروتوتایپ یک شئ مشخص کننده کلاسیه که کلاس ایجاد کننده شئ مورد نظر از اون به ارث رسیده است. برای همین من برای مشخص کردن اینکه کلاس Square از کلاس Rectangle ارث بری کرده نیاز به این دارم که یک شئ از کلاس Rectangle به پروتوتایپ کلاس Square نسبت بدم تا این زنجیره پروتوتایپ هامون حفظ شه! گفته بودیم هم که آخرین حلقه این زنجیره کلاس Object است.

آموزش قسمت یازدهم جاوا اسکریپت Java Script

ساختاری از یک شئ را در شکل زیر ملاحظه می کنید:

آموزش قسمت یازده جاوا اسکریپت Java Script

تفاوت prototype و __proto__ چیست؟

اگر شما مستقیما کلاس (مثلا Rectangle) رو به watch اضافه نمایید خواهید دید که یک مقدار prototype و یک مقدار __proto__ دارد. حالا تفاوت این دو مقدار در چیست؟ هنگامی که بخواهیم برای کلاس پروتوتایپ تعریف کنیم یا اینکه به پروتوتایپ های آن دسترسی داشته باشیم از prototype استفاده می کنیم، در حقیقت این دسترسی از طریق خود کلاس میسر است، اما زمانی که بخواهیم از طریق شئ ایجاد شده از یک کلاس به پروتوتایپ آن شئ دسترسی داشته باشیم ار شئ __proto__ استفاده می کنیم. در حقیقت این شئ، همان پروتوتایپی است که در کلاس تعریف کرده بودیم که دسترسی به پروتوتایپ ها را از طریق شئ برای ما میسر می سازد.

در هنگام add to watch کردن خود کلاس با __proto__ نیز مواجهد می شوید، اما در اینجا دیگر یک شئ نیست و در واقع تابعی است که شئ __proto__ را در شئ به ما ارائه می دهد.

در آخر یادآور میشوم که مفهوم کلاس در جاوااسکریپت وجود ندارد و استفاده من از این اصطلاح تنها به دلیل ملموس تر شدن آموزش بوده و همانطور که قبلا گفته بودم معادل آن مفهومی با عنوان تابع سازنده یا Constructor Function ر داریم. پس بعضا در این آموزش این مفاهیم به جای هم استفاده شدند.

در جلسه آینده، مثالی کاربردی از کلاسها و وراثت بین آنها خواهیم زد.

اگر سوالی هست در گروه برنامه نویسان مطرح کنید و من رو منشن کنید@AkramKarimi

خسته نباشید

دانلود pdf قسمت یازدهم آموزش جاوا اسکریپت