کلاس ها در زبان برنامه نویسی TypeScript
TypeScript همان جاوا اسکریپت شیء گرا است و از ویژگی های برنامه نویسی شیء گرا مانند کلاس ها، اینترفیس ها و غیره پشتیبانی می کند. از دیدگاه برنامه نویسی شیء گرا (OOP)، کلاس یک طرح برای ایجاد اشیاء است.
ایجاد یک کلاس
در زبان برنامه نویسی TypeScript به منظور ایجاد کلاس از کلمه کلیدی class استفاده می کنیم. در زیر می توانید سینتکس مربوطه را مشاهده کنید:
1 2 3 | class class_name { //class scope } |
نام کلاس بعد از کلمه کلیدی class مشخص می شود. یک کلاس میتواند شامل موارد زیر باشد:
- فیلدها (Fields): هر متغیری که در داخل کلاس تعریف شود، یک فیلد محسوب می شود.
- سازنده ها (Constructors): مسئول تخصیص حافظه به نمونه های ایجاد شده از کلاس و مقدار دهی اولیه به فیلدها هستند.
- توابع یا متدها (Functions): توابع عملیاتی که یک شیء می تواند انجام دهد را نشان می دهند.
موارد فوق در کنار یک دیگر اعضای کلاس را تشکیل می دهند. کلاس Person را در نظر بگیرید:
1 2 | class Person { } |
کد فوق بعد از کامپایل شدن:
1 2 3 4 5 6 | //Generated by typescript 1.8.10 var Person = (function () { function Person() { } return Person; }()); |
مثال (اعلان یک کلاس):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class Car { //field engine:string; //constructor constructor(engine:string) { this.engine = engine } //function disp():void { console.log("Engine is : "+this.engine) } } |
در مثال فوق یک کلاس به نام Car اعلان شده است که شامل یک فیلد به نام engine است (در هنگام تعریف فیلد از کلمه کلیدی var استفاده نمی شود). کلمه کلیدی this به شیء جاری از کلاس اشاره دارد. در کد فوق چون نام پارامتر سازنده با فیلد یکی است، برای جدا کردن این دو از کلمه کلیدی this استفاده شده است. disp() یک تابع ساده است که مقدار فیلد engine را در کنسول چاپ می کند (کلمه کلیدی function استفاده نشده است). کد فوق بعد از کامپایل شدن:
1 2 3 4 5 6 7 8 9 10 11 12 13 | //Generated by typescript 1.8.10 var Car = (function () { //constructor function Car(engine) { this.engine = engine; } //function Car.prototype.disp = function () { console.log("Engine is : " + this.engine); }; return Car; }()); |
نمونه سازی از کلاس
برای ایجاد نمونه از یک کلاس از کلمه کلیدی new به همراه نام کلاس استفاده می کنیم. در زیر می توانید سینتکس مربوط به نحوه نمونه سازی از یک کلاس را مشاهده کنید.
1 | var object_name = new class_name([ arguments ]) |
- کلمه کلیدی new مسئول نمونه سازی است.
- بعد از آن سازنده کلاس فراخوانی می شود.
مثال:
1 | var obj = new Car("Engine 1") |
دسترسی به اعضای کلاس
برای دسترسی به اعضای کلاس می توانیم از ‘.’ (نقطه) استفاده کنیم. مانند نمونه زیر:
1 2 3 4 5 | //accessing an attribute obj.field_name //accessing a function obj.function_name() |
مثال:
در مثال زیر موارد گفته شده در بالا استفاده شده اند:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class Car { //field engine:string; //constructor constructor(engine:string) { this.engine = engine } //function disp():void { console.log("Function displays Engine is : "+this.engine) } } //create an object var obj = new Car("XXSY1") //access the field console.log("Reading attribute value Engine as : "+obj.engine) //access the function obj.disp() |
کد فوق بعد از کامپایل شدن:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | //Generated by typescript 1.8.10 var Car = (function () { //constructor function Car(engine) { this.engine = engine; } //function Car.prototype.disp = function () { console.log("Function displays Engine is : " + this.engine); }; return Car; }()); //create an object var obj = new Car("XXSY1"); //access the field console.log("Reading attribute value Engine as : " + obj.engine); //access the function obj.disp(); |
خروحی مثال:
1 2 | Reading attribute value Engine as : XXSY1 Function displays Engine is : XXSY1 |
وراثت (Inheritance)
زبان TypeScript از مفهوم وراثت پشتیبانی می کند. وراثت قابلیت یک برنامه در ایجاد یک کلاس جدید از روی یک کلاس موجود است. کلاسی که آن را برای ایجاد کلاس جدید توسعه می دهیم، کلاس پدر و کلاس جدید ساخته از روی کلاس پدر، کلاس فرزند یا مشتق شده نامیده می شود.
برای اینکه یک کلاس از کلاس دیگر ارث بری کند، باید از کلمه کلیدی extends استفاده کنیم. کلاس فرزند تمام اعضای کلاس پدر به جز اعضای private را به ارث می برد. سینتکس مربوط به ارث بری از یک کلاس:
1 | class child_class_name extends parent_class_name |
مثال:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Shape { Area:number constructor(a:number) { this.Area = a } } class Circle extends Shape { disp():void { console.log("Area of the circle: "+this.Area) } } var obj = new Circle(223); obj.disp() |
کد فوق بعد از کامپایل شدن:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | //Generated by typescript 1.8.10 var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var Shape = (function () { function Shape(a) { this.Area = a; } return Shape; }()); var Circle = (function (_super) { __extends(Circle, _super); function Circle() { _super.apply(this, arguments); } Circle.prototype.disp = function () { console.log("Area of the circle: " + this.Area); }; return Circle; }(Shape)); var obj = new Circle(223); obj.disp(); |
خروجی مثال:
1 | Area of the Circle: 223 |
در مثال فوق یک کلاس به نام Shape ایجاد شده است که کلاس Circle از آن ارث بری می کند. چون کلاس Circle از Shape ارث بری کرده است، می تواند به اعضای آن مانند area دسترسی داشته باشد.
انواع وراثت
- وراثت تکی (Single): کلاس فرزند حداکثر می تواند یک کلاس والد داشته باشد.
- وراثت چندگانه (Multiple): کلاس فرزند می تواند از چند کلاس ارث بری کند (در تایپ اسکریپت پشتیبانی نمی شود).
- وراثت چند سطحی (Multi-level): در مثال زیر نحوه ارث بری چند سطحی نشان داده شده است:
1 2 3 4 5 6 7 8 9 10 | class Root { str:string; } class Child extends Root {} class Leaf extends Child {} //indirectly inherits from Root by virtue of inheritance var obj = new Leaf(); obj.str ="hello" console.log(obj.str) |
در کد فوق، کلاس Leaf به شکل ارث بری چندگانه از کلاس Root و Child مشتق شده است. کد بالا بعد از کامپایل شدن:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | //Generated by typescript 1.8.10 var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var Root = (function () { function Root() { } return Root; }()); var Child = (function (_super) { __extends(Child, _super); function Child() { _super.apply(this, arguments); } return Child; }(Root)); var Leaf = (function (_super) { __extends(Leaf, _super); function Leaf() { _super.apply(this, arguments); } return Leaf; }(Child)); var obj = new Leaf(); obj.str = "hello"; console.log(obj.str); |
خروجی مثال:
1 | hello |
سربارگذاری تابع (Method Overriding)
سربارگذاری تابع مکانسیمی است که در آن کلاس فرزند می تواند تابع تعریف شده در کلاس پدر را، دوباره تعریف کند. برای درک بهتر به مثال زیر توجه کنید:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class PrinterClass { doPrint():void { console.log("doPrint() from Parent called…") } } class StringPrinter extends PrinterClass { doPrint():void { super.doPrint() console.log("doPrint() is printing a string…") } } var obj = new StringPrinter() obj.doPrint() |
کلمه کلیدی super برای اشاره به کلاس والد استفاده می شود. از این کلمه کلیدی می توانیم برای اشاره به متغیر، پراپرتی و یا تابع موجود در کلاس والد اشاره کنیم.
در خط 13 کد بالا، متد doPrint که در کلاس والد تعریف شده است، فراخوانی می شود.
کد فوق بعد از کامپایل شدن:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | //Generated by typescript 1.8.10 var __extends = (this && this.__extends) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; var PrinterClass = (function () { function PrinterClass() { } PrinterClass.prototype.doPrint = function () { console.log("doPrint() from Parent called…"); }; return PrinterClass; }()); var StringPrinter = (function (_super) { __extends(StringPrinter, _super); function StringPrinter() { _super.apply(this, arguments); } StringPrinter.prototype.doPrint = function () { _super.prototype.doPrint.call(this); console.log("doPrint() is printing a string…"); }; return StringPrinter; }(PrinterClass)); var obj = new StringPrinter(); obj.doPrint(); |
خروجی:
1 2 | doPrint() from Parent called… doPrint() is printing a string… |
کلمه کلیدی static
کلمه کلیدی static برای دسترسی به اعضای یک کلاس، بدون نمونه سازی از آن استفاده می شود. عضوی که به صورت static تعریف شود، تا زمانی که اجرای برنامه تمام نشود، مقدار خود را حفظ می کند. برای دسترسی به اعضای static باید از نام کلاس به همراه نقطه استفاده کنیم. مثال:
1 2 3 4 5 6 7 8 9 10 | class StaticMem { static num:number; static disp():void { console.log("The value of num is"+ StaticMem.num) } } StaticMem.num = 12 // initialize the static variable StaticMem.disp() // invoke the static method |
کد فوق بعد از کامپایل شدن:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //Generated by typescript 1.8.10 var StaticMem = (function () { function StaticMem() { } StaticMem.disp = function () { console.log("The value of num is" + StaticMem.num); }; return StaticMem; }()); StaticMem.num = 12; // initialize the static variable StaticMem.disp(); // invoke the static method |
خروجی مثال:
1 | The value of num is 12 |
عملگر instanceof
عملگر instanceof زمانی که نوع یک شیء برابر با نوع مشخص شده باشد، مقدار true باز میگرداند. مثال:
1 2 3 4 | class Person{ } var obj = new Person() var isPerson = obj instanceof Person; console.log(" obj is an instance of Person " + isPerson); |
کد فوق بعد از کامپایل شدن:
1 2 3 4 5 6 7 8 9 10 | //Generated by typescript 1.8.10 var Person = (function () { function Person() { } return Person; }()); var obj = new Person(); var isPerson = obj instanceof Person; console.log(" obj is an instance of Person " + isPerson); |
خروجی مثال:
1 | obj is an instance of Person True |
مخفی کردن اعضای کلاس
یک کلاس می تواند مشخص کند که کدام یک از اعضای آن، خارج از آن کلاس در دسترس باشند. این قابلیت Encapsulation نیز نامیده می شود. به منظور پیاده سازی مفهوم Encapsulation از access modifier ها استفاده می کنیم. access modifier ها سطح دسترسی اعضای کلاس را در خارج و کلاس های مشتق شده مشخص می کنند. در جدول زیر سطوح دسترسی موجود در زبان TypeScript را مشاهده می کنید:
ردیف | توضیحات |
1 | public اعضایی که به شکل public تعریف شوند در هر جایی قابل دسترسی هستند. اعضای کلاس ها به طور پیشفرض public هستند. |
2 | private اعضایی که به شکل private تعریف شوند، فقط در داخل همان کلاس قابل دسترسی هستند. |
3 | protected اعضایی که به شکل protected تعریف شوند، در داخل همان کلاس و کلاس مشتق شده قابل دسترسی هستند. |
مثال:
مثال زیر نحوه مخفی کردن اعضای یک کلاس را نشان می دهد:
1 2 3 4 5 6 7 8 | class Encapsulate { str:string = "hello" private str2:string = "world" } var obj = new Encapsulate() console.log(obj.str) //accessible console.log(obj.str2) //compilation Error as str2 is private |
کلاس فوق دو فیلد با نام های str و str2 دارد که اولی به صورت public و دومی به صورت private تعریف شده است. اگر در خارج از کلاس بخواهیم به فیلد str2 دسترسی داشته باشیم، با خطای کامپایلر رو به رو خواهیم شد.
کلاس ها و اینترفیس ها
کلاس ها همچنین می توانند اینترفیس ها را نیز پیدا سازی کنند. مانند نمونه زیر:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | interface ILoan { interest:number } class AgriLoan implements ILoan { interest:number rebate:number constructor(interest:number,rebate:number) { this.interest = interest this.rebate = rebate } } var obj = new AgriLoan(10,1) console.log("Interest is : "+obj.interest+" Rebate is : "+obj.rebate ) |
کد فوق بعد از کامپایل شدن:
1 2 3 4 5 6 7 8 9 10 11 | //Generated by typescript 1.8.10 var AgriLoan = (function () { function AgriLoan(interest, rebate) { this.interest = interest; this.rebate = rebate; } return AgriLoan; }()); var obj = new AgriLoan(10, 1); console.log("Interest is : " + obj.interest + " Rebate is : " + obj.rebate); |
خروجی مثال:
1 | Interest is : 10 Rebate is : 1 |
هیچ نظری ثبت نشده است