چهارشنبه, 22 آذر 1396

آموزش تایپ اسکریپت

همه چیز در باره تایپ اسکریپت

کلاس ها در تایپ اسکریپت(#2)

Parameter properties

 

class Octopus {
    readonly name: string;
    readonly numberOfLegs: number = 8;
    constructor (theName: string) {
        this.name = theName;
    }
}
let dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // error! name is readonly.

 

در مثال بالا،ما تا به حال به یک عضو "Readonly name" و یک پارامتر سازنده "theName" در "کلاس octopus اعلام کردیم،و ما بلافاصله name را به theName  مقداردهی کردیم.این یک عمل بسیار رایج محسوب می شود.ویژگی های پارامتر به شما اجازه ایجاد و مقداردهی اولیه یک عضو در یک مکان را می دهد.در اینجا می خواهیم در کلاس قبلی octopus با استفاده از خصوصیات پارامتر ها تجدید نظر کنیم.

class Octopus { readonly numberOfLegs: number = 8; constructor(readonly name: string) { } }

 

توجه داشته باشید که در کل،  theName را حذف کردیم  و فقط با فرمت مختصر پارامتر readonly name: string  در سازنده، هم آن را ایجاد کردیم و  به عضو name مقداردهی کردیم.در واقع، در یک مکان  هم تعریف و هم مقداردهی انجام دادیم.

 

Parameter properties با پیشونددهی پارامتر سازنده با readonly یا نحوه دسترسی  و یا هر دو تعریف می شوند. همان طور که برای تعریف و مقداردهی اولیه اعضای private از کلمه private  استفاده کردیم می توانیم برای Public , protected , readonly نیز استفاده کنیم.

 

accessors دسترسی  ها

 

تایپ اسکریپت از getters/setters به عنوان راهی برای حائل شدن به دسترسی به اعضای یک شی پشیبانی می کند.این به شما اجازه میدهد که کنترل بهتری به نحوه دسترسی به اعضای اشیا بدهید.

 

در ابتدا با یک مثال بدون set و get شروع می کنیم:

Lclass Employee { fullName: string; } let employee = new Employee(); employee.fullName = "Bob Smith"; if (employee.fullName) { console.log(employee.fullName); }

 

در حالی که اجازه دادن به کاربر برای تنظیم مستقیم FullName به صورت دستی زیبا به نظر می رسد، اگر کاربر نام ها را به صورت ناگهانی تغییر دهند، برای ما ایجاد دردسر می کند.

 

در این نسخه، قبل از اینکه اجازه ویرایش کارمند را به کاربر بدهیم ، ابتدا بررسی می کنیم تا مطمئن شویم که کاربر رمز عبور محرمانه برای دسترسی دارد. این کار را با جایگزین کردن دسترسی مستقیم به نام و نام خانوادگی  با مجموعه ای که کد عبور را بررسی می کند، انجام می دهیم. ما  get  مربوطه را اضافه می کنیم تا  اجازه دهیم که مثال قبلی به صورت یکپارچه کار کند.

 

let passcode = "secret passcode"; class Employee { private _fullName: string; get fullName(): string { return this._fullName; } set fullName(newName: string) { if (passcode && passcode == "secret passcode") { this._fullName = newName; } else { console.log("Error: Unauthorized update of employee!"); } } } let employee = new Employee(); employee.fullName = "Bob Smith"; if (employee.fullName) { console.log(employee.fullName); }

برای اثبات به خودمان که دسترسی ما با رمز عبور بررسی می شود، ما می توانیم رمز عبور را تغییر دهیم و ببینم که زمانی که رمز عبور درست نیست، آیا پیغام خطایی مبتنی بر این که شما دسترسی به ویرایش کارمندان را ندارید، دریافت می کنیم یا نه.

 

در مورد دسترسی ها چند چیز را در نظر داشته باشید:

اول، accessors (دسترسی ها) نیاز دارند که شما کامپایلر را به خروجی ECMAScript 5 یا بالاتر تنظیم کنید. ECMAScript 3 پشتیبانی نمی شود.دوم، accessors با get  و بدون set  به صورت اتوماتیک readonly محسوب می شوند. این مورد زمانی مفید است که فایل d.ts از کدتان را تولید کنید چرا که کاربران این ویژگی می فهمند که نمی توانند آن را تغییر دهند.

دسترسی شما نیاز به مجموعه ای از کامپایلر دارد تا  به خروجی متداول 5 یا بالاتر

 

Static Properties ویژگی های ایستا

تا به اینجا تنها در مورد اعضای یک نمونه از کلاس صحبت کردیم، زمانی که نمونه ای از شی ساخته می شود، نشان داده می شود. هم چنین می توانین اعضای ایستا از کلاس را ایجاد کنیم که تنها درون کلاس و نه در نمونه ها نمایان هستند . در این مثال، یک مقدار عمومی در تمامی گرید ها بیان می کنیم.  هر نمونه به این مقدار(ایستا) در زمان prepending کلاس دسترسی پیدا می کند. همان طور که برای دسترسی به نمونه کلاس که از this. استفاده می کردیم، در اینجا از پیشوند .Grid  در ابتدای دسترسی  به اعضای استایتک باید استفاده کنیم.

 

class Grid { static origin = {x: 0, y: 0}; calculateDistanceFromOrigin(point: {x: number; y: number;}) { let xDist = (point.x - Grid.origin.x); let yDist = (point.y - Grid.origin.y); return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale; } constructor (public scale: number) { } } let grid1 = new Grid(1.0); // 1x scale let grid2 = new Grid(5.0); // 5x scale console.log(grid1.calculateDistanceFromOrigin({x: 10, y: 10})); console.log(grid2.calculateDistanceFromOrigin({x: 10, y: 10}));

 

Abstract Classes کلاس های انتزاعی

 

کلاس های Abstract کلاس های اصلی هستند که دیگر کلاس ها ممکن است از آن مشتق شوند. از این کلاس ها نمی توان به صورت مستقیم نمونه سازی کرد. بر خلاف اینترفیس ها، کلاس های انتزاعی می تواند شامل جزئیات پیاده سازی برای اعضایش باشد.کلمه کلیدی Abstract  برای کلاس های Abstract استفاه می شود.(همانند متد های Abstract درون کلاس های Abstract)

abstract class Animal { abstract makeSound(): void; move(): void { console.log("roaming the earth..."); } }

 متد هایی که در کلاس های انتزاعی (abstract)  به صورت انتزاعی نشان گذاری شده اند،نباید  پیاده سازی داشته باشند و  باید در کلاس های مشتق شده پیاده سازی شوند.نحوه به اشتراک گذاری متدهای انتزاعی (از نظر شیوه نوشتار) بسیار شبیه به متدهای اینترفیس است.هر دو، ساختار متد ها را بیان می کنند بدون اینکه شامل بدنه متد باشند. اگر چه متدهای انتزاعی باید شامل کلمه کلید abstract  و ممکن است به صورت اختیاری شامل نحوه دسترسی نیز باشند.

 

abstract class Department { constructor(public name: string) { } printName(): void { console.log("Department name: " + this.name); } abstract printMeeting(): void; // must be implemented in derived classes } class AccountingDepartment extends Department { constructor() { super("Accounting and Auditing"); // constructors in derived classes must call super() } printMeeting(): void { console.log("The Accounting Department meets each Monday at 10am."); } generateReports(): void { console.log("Generating accounting reports..."); } } let department: Department; // ok to create a reference to an abstract type department = new Department(); // error: cannot create an instance of an abstract class department = new AccountingDepartment(); // ok to create and assign a non-abstract subclass department.printName(); department.printMeeting(); department.generateReports(); // error: method doesn't exist on declared abstract type

Advanced Techniques تکنیک های پیشرفته

 

 توابع سازنده Constructor functions

 زمانی که شما کلاسی را در تایپ اسکریپت تعریف می کنید،در واقع شما چندین تعریف را همزمان انجام می دهید. اول از همه بیان نوع نمونه کلاس است.

 

class Greeter { greeting: string; constructor(message: string) { this.greeting = message; } greet() { return "Hello, " + this.greeting; } } let greeter: Greeter; greeter = new Greeter("world"); console.log(greeter.greet());

در اینجا، زمانی که شما let greeter: Greeter را بیان می کنید، از Greerter به عنوان نمونه از کلاس Greeter استفاده می کنید.

 

ما هم چنین توابع سازنده نیز ایجاد می کنیم. توابع سازنده، توابعی هستند که زمانی که از کلمه new برای ایجاد یک نمونه از کلاس استفاده می کنیم، فراخوانی می شود.برای دیدن اینکه چی اتفاقی می افتد بهتر است نگاهی به جاوااسکریپت تولید شده از مثال بالا بیندازیم.

 

let Greeter = (function () { function Greeter(message) { this.greeting = message; } Greeter.prototype.greet = function () { return "Hello, " + this.greeting; }; return Greeter; })(); let greeter; greeter = new Greeter("world"); console.log(greeter.greet());

 در اینجا، let Greeter در حال اختصاص داده شدن به تابع سازنده است. زمانی که ما new را صدا می زنیم و این تابع را اجرا می کنیم، یک نمونه از کلاس را دریافت می کنیم. تابع سازنده هم چنین تمامی اعضای استاتیک از کلاس را شامل می شود. برای هر کلاس، وجه نمونه و وجه استاتیک وجود دارد.

 

 بیاید این مثال را کمی تغییر بدهیم تا این تفاوت ها مشخص شوند.

 

class Greeter { static standardGreeting = "Hello, there"; greeting: string; greet() { if (this.greeting) { return "Hello, " + this.greeting; } else { return Greeter.standardGreeting; } } } let greeter1: Greeter; greeter1 = new Greeter(); console.log(greeter1.greet()); let greeterMaker: typeof Greeter = Greeter; greeterMaker.standardGreeting = "Hey there!"; let greeter2: Greeter = new greeterMaker(); console.log(greeter2.greet());

در این مثال greeter1 همانند قبل عمل می کند.ما کلاس  greeter را معرفی می کنیم و از این شی استفاده می کنیم. این چیزی است که قبلا دیدید.

سپس، ما کلاس را به صورت مستقیم استفاده می کنیم. در اینجا ما متغیر جدید ایجاد می کنیم که greeterMaker نامیده می شود. این متغیر کلاس را درون خودش نگه می دارد، یا به روش دیگر تابع سازنده اش را صدا می زدند. در اینجا ما typeof Greeter  را استفاده کردیم که نوع کلاس greeter خودش را به جای نوع نمونه می دهد. دقیقا نوع فراخوانی شده greeter را می دهد، که نوع تابع سازنده است. این نوع تمامی اعضای استاتیک از greeter را همراه با سازنده که نمونه کلاس greeter را ایجاد می کند را شامل می شود.ما این کار را با استفاده از new  در  greeterMaker نشان دادیم (با ایجاد کردن نمونه کلاس Greeter  و فراخوانی آن ها همانند قبل).

 

استفاده از کلاس به عنوان اینترفیس

Using a class as an interface

 همانگونه که در بخش قبلی گفتیم، تعریف کلاس دو چیز را ایجاد می کند: یک نشان دادن نوع نمونه کلاس و توابع سازنده.بدلیل اینکه توابع، نوع را مشخص می کنند شما می توانید درست همان جاهایی که از اینترفیس استفاده می کنید از توابع نیز استفاده کنید.

class Point { x: number; y: number; } interface Point3d extends Point { z: number; } let point3d: Point3d = {x: 1, y: 2, z: 3};