آموزش استفاده از ماژولها در TypeScript
در این مقاله میخوانید
ماژولها راهی برای سازماندهی کدهای شما و تبدیل به بخشهای کوچکتر هستند که باعث میشوند کدهای خود را بهتر مدیریت کنید. در سالهای اخیر، چندین استراتژی مختلف برای ماژولارسازی کدهای جاوااسکریپت بهوجود آمده است. یکی از این استراتژیها تایپاسکریپت (TypeScript) نام دارد که بهکمک ECMAScript بهوجود آمده است تا سیستم ماژولار استانداردی برای برنامههای جاوااسکریپتی ارائه دهد.
تایپاسکریپت از ایجاد و استفاده ماژولها بهصورت یکپارچه و سینتکسی (Syntax) همانند ES Module پشتیبانی میکند که به برنامهنویسان اجازه میدهد کدهایشان را در فایلهای متفاوت دستهبندی و برای استفاده در سیستمهای جاوااسکریپتی متفاوت مانند Node.js (CommonJS), require.js (AMD), UMD, SystemJS, or ECMAScript 2015 native modules (ES6 آماده سازند.
در این مقاله آموزشی از بلاگ پارس پک، ماژولهای متفاوتی در TypeScript ایجاد و از آنها استفاده میکنیم. همچنین، شما را با استاندارد استفاده از ماژولها و شیوه ایجاد آنها با شیءگرایی در جاوااسکریپت و نیز نحوه استفاده از Import و Export در TypeScript آشنا میکنیم.
پیشنیازها
برای شروع آموزش، باید پیشنیازهای زیر را فراهم کنید:
- برای اجرای کدهای TypeScript باید Node و npm یا yarn را نصب کنید. در این آموزش، از Node.js نسخه 14.3.0 و npm نسخه 6.14.5 استفاده کردهایم.
- دانش کافی درباره JavaScript و ES6+ و Imports/Exports
- بهتر است از ویرایشگری استفاده کنید که TypeScript را پشتیبانی کند (مانند Visual Studio Code) تا خطاهای کد را به شما نشان دهد. این پیشنیاز ضروری نیست؛ اما نصب آن به درک بهتر کد و کدنویسی بهتر کمک میکند.
نکته: در این آموزش، از TypeScript ورژن 4.2.2 در تمام کدهای نوشتهشده استفاده کردهایم.
راهاندازی پروژه
در این مرحله، پروژهای تستی (Sample) ایجاد میکنیم که شامل دو کلاس کوچک برای مدیریت عملیاتهای برداری است: کلاس Vector2 و Vector3. کلاسهایی که ایجاد میکنیم، هرکدام تنها یک عملیات انجام خواهند داد. درادامه، از این کلاسها در فایلهای دیگر استفاده میکنیم.
در ابتدا، پوشهای برای پروژه خود ایجاد کنید:
mkdir vector_project
پس از ایجاد پوشه، وارد آن شوید:
cd vector_project
اکنون در پوشه پروژه خود هستید. اپلیکیشن Node.js خود را با استفاده از npm ایجاد کنید:
npm init
با این کار فایل package.json در پوشه پروژه شما ایجاد میشود. پسازآن، TypeScript را بهعنوان Dependency به پروژه خود اضافه کنید:
npm install [email protected] --save-dev
با این کار، کامپایلر TypeScript با تنظیمات پیشفرض روی پروژه شما نصب میشود. برای ویرایش تنظیمات کامپایلر TypeScript، باید فایل پیکربندی جداگانه ایجاد کنید. برای انجام این کار، فایلی به نام tsconfig.json در پروژهتان ایجاد و آن را باز کنید. برای اینکه پروژه شما با تمرینات این آموزش همخوانی داشته باشد، تنظیمات زیر را اضافه کنید:
{ "compilerOptions": { "target": "ES6", "module": "CommonJS", "outDir": "./out", "rootDir": "./src", "strict": true } }
با استفاده از این کد، چندین پیکربندی را برای TypeScript تنظیم میکنید:
- “target”:”ES6″: محیطی را مشخص میکند که برای کامپایل به آن نیاز دارید.
- “module”:”CommonJS”: تعیینکننده نام ماژول شماست.
- “outDir”:”./out” و “rootDir”:”./src”: مشخصکننده پوشههای ورودیوخروجی کامپایلر TypeScript است.
- “strict”: true: قابلیت strict برای سختگیری در کدها فعال میکند.
نکته: با راهاندازی و پیکربندی پروژه، میتوانید اولین ماژول خود را ایجاد کنید.
ایجاد ماژول در TypeScript با استفاده از Export
در این بخش با پیروی از سینتکس TypeScript، ماژولهایی را برای آن ایجاد میکنیم. بهطور پیشفرض فایلهای موجود در پروژه TypeScript دسترسی جهانی (Global) دارند. این یعنی هر متغیر، کلاس، تابع یا ساختار دیگری که در فایلی ذخیره میشود، بهصورت جهانی دردسترس قرار دارد و در همه فایلهای دیگر میتوان از آن استفاده کرد. بهمحض اینکه استفاده از ماژولها را در فایلی شروع میکنید، آن فایل از محدوده ماژول برخوردار میشود و دیگر بهصورت سراسری دردسترس نخواهد بود.
برای اثبات این عمل، اولین کلاس خود را با نام Vector2 ایجاد میکنیم. برای این کار، ابتدا پوشه src را در پروژهتان ایجاد کنید:
mkdir src
این پوشه، پوشهای است که در فایل پیکربندی (tsconfig.json) خود تنظیم کردهاید. داخل این پوشه فایل جدیدی به نام vector2.ts ایجاد کنید و سپس کلاس خود را در آن بنویسید:
class Vector2 { constructor(public x: number, public y: number) {} add(otherVector2: Vector2) { return new Vector2(this.x + otherVector2.x, this.y + otherVector2.y); } }
در این کد، کلاسی به نام Vector2 ایجاد کردیم که دو عدد را بهعنوان پارامتر ورودی دریافت و برای مشخصکردن x و y بردار بهکار میبرد. ازآنجاکه فایلتان درحالحاضر ماژول نیست، فایل Vector2 شما بهصورت جهانی دردسترس است. برای تبدیل فایل خود به ماژول، فقط باید کلاس Vector2 خود را به Export تبدیل کنید:
export class Vector2 { constructor(public x: number, public y: number) {} add(otherVector2: Vector2) { return new Vector2(this.x + otherVector2.x, this.y + otherVector2.y); } }
فایل src/vector2.ts اکنون ماژولی است که تنها کلاس Vector2 را صادر میکند. فایل خود را ذخیره کنید و ببندید. درادامه، کلاس Vector3 خود را ایجاد کنید. برای این کار، فایل vector3.ts را در پوشه src/ ایجاد کنید و کد زیر را درون آن قرار دهید:
export class Vector3 { constructor(public x: number, public y: number, public z: number) {} add(otherVector3: Vector3) { return new Vector3( this.x + otherVector3.x, this.y + otherVector3.y, this.z + otherVector3.z ); } }
این کد کلاسی شبیه به Vector2 ایجاد میکند، با این تفاوت که با استفاده از آرگومان ورودی سوم یعنی z، نمودارهای سهبعدی ایجاد میکند. دقت کنید کلمه Export را قبل از کلاس آن بهکار بردیم و این بهمعنای ماژولاربودن این کلاس است.
حالا دو فایل vector2.ts و vector3.ts دارید که هر دو ماژول هستند. هر فایل یک کلاس Export بردارساز دارد. در بخش بعدی، این ماژولها را با دستور Import وارد فایلهای دیگر و از ماژولها استفاده خواهیم کرد.
آموزش کامل ساخت و بهکارگیری اینترفیس در Typescript را در مقاله زیر بخوانید.
استفاده از ماژولها در TypeScript با Import
در بخش قبل، توانستید ماژول TypeScript ایجاد کنید. در این بخش، باید از ماژولهای ساختهشده در فایلهای دیگر استفاده کنید.
یکی از سناریوهای رایج هنگام کار با ماژولها در TypeScript این است که فایل واحدی برای جمعآوری ماژولها داشته باشیم و آن فایل واحد را مجدداً Export کنیم. برای پیادهسازی این سناریو، فایل جدیدی به نام vectors.ts در دایرکتوری src/ ایجاد و آن را باز میکنیم:
import { Vector2 } from "./vector2"; import { Vector3 } from "./vector3";
برای واردکردن ماژولها به پروژه، از دستور Import استفاده و آدرس فایل ماژول را از مسیر فایل فعلی وارد میکنیم. در اینجا، هر دو ماژول را از /vector2. و /vector3. وارد میکنید که مسیرهای آنها از فایل فعلی به فایلهای src/vector2.ts و src/vector3.ts اشاره میکند.
حال که ماژول بردارها را وارد کردید، میتوانید آنها را بهعنوان ماژول Export کنید:
import { Vector2 } from "./vector2"; import { Vector3 } from "./vector3"; export { Vector2, Vector3 };
دستور {} export به شما امکان میدهد چندین شناسه را صادر کنید. در این حالت، کلاسهای Vector2 و Vector3 را با استفاده از Export صادر میکنید. همچنین، از دو عبارت Export جداگانه میتوانید استفاده کنید؛ مانند:
import { Vector2 } from "./vector2"; import { Vector3 } from "./vector3"; export { Vector2 }; export { Vector3 };
این کد نیز همانند کد قبل عمل میکند. ازآنجاکه در این فایل فقط دو ماژول وارد و بدون هیچ تغییری صادر میشوند، از شکل کوتاهتر این کد میتوانید استفاده کنید:
export { Vector2 } from "./vector2"; export { Vector3 } from "./vector3";
در اینجا، عبارت Import ضمنی است و کامپایلر TypeScript بهصورت خودکار آن را قرار میدهد و بلافاصله آن را Export میکند.
فایل جدیدی به نام src/index.ts ایجاد و سپس فایل را باز کنید و کد زیر را بنویسید:
import { Vector2, Vector3 } from "./vectors"; const vec2a = new Vector2(1, 2); const vec2b = new Vector2(2, 1); console.log(vec2a.add(vec2b)); const vec3a = new Vector3(1, 2, 3); const vec3b = new Vector3(3, 2, 1); console.log(vec3a.add(vec3b));
در این کد، شما در حال واردکردن و استفاده از هر دو کلاس بردار از فایل src/vectors.ts هستید که از مسیر /vectors. خوانده میشود. سپس، چند نمونه بردار ایجاد و آنها را با تابع ()add با یکدیگر جمع کنید.
هنگام واردکردن نامهای Exportشده، میتوانید از نام مستعار دیگری نیز استفاده کنید که برای جلوگیری از وجود نامهای تکراری در فایل بهکار برده میشود. برای امتحانکردن این موضوع، تغییرات زیر را در فایل خود اعمال کنید:
import { Vector2 as Vec2, Vector3 as Vec3 } from "./vectors"; const vec2a = new Vec2(1, 2); const vec2b = new Vec2(2, 1); console.log(vec2a.add(vec2b)); const vec3a = new Vec3(1, 2, 3); const vec3b = new Vec3(3, 2, 1); console.log(vec3a.add(vec3b));
در اینجا، از کلمه as بهمنظور مشخصکردن نام مستعار Vec2 و Vec3 برای کلاسهای واردشده استفاده کردیم. ازآنجاکه فایل /vectors. فقط دو کلاس Vector3 و Vector2 را صادر میکند، همه دادههای موجود در فایل /vectors. را میتوانید وارد کنید:
import * as vectors from "./vectors"; const vec2a = new vectors.Vector2(1, 2); const vec2b = new vectors.Vector2(2, 1); console.log(vec2a.add(vec2b)); const vec3a = new vectors.Vector3(1, 2, 3); const vec3b = new vectors.Vector3(3, 2, 1); console.log(vec3a.add(vec3b));
در کد بالا، از import * as برای واردکردن هرآنچه ماژول بهعنوان متغیر Export میکند، بهره بردید. همچنین، باید نحوه استفاده از کلاسهای Vector2 و Vector3 را تغییر دهید؛ زیرا اکنون کلاسها داخل شیء vectors قرار دارند که در هنگام واردکردن ایجاد میشود.
فایل را ذخیره و پروژه را با استفاده از tsc کامپایل کنید:
npx tsc
کامپایلر TypeScript قرار است پوشه out/ را ایجاد کند (باتوجهبه گزینه compileOptions.outDir که در فایل tsconfig.json تنظیم کردهاید). سپس، فایل خروجی جاوااسکریپت را درون آن قرار دهد.
فایل کامپایلشده موجود در out/index.js را در ویرایشگر کد خود باز کنید:
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const vectors = require("./vectors"); const vec2a = new vectors.Vector2(1, 2); const vec2b = new vectors.Vector2(2, 1); console.log(vec2a.add(vec2b)); const vec3a = new vectors.Vector3(1, 2, 3); const vec3b = new vectors.Vector3(3, 2, 1); console.log(vec3a.add(vec3b));
ازآنجاکه گزینه compilerOptions.module در فایل tsconfig.json شما روی CommonJS تنظیم شده است، کامپایلر TypeScript کدی را ایجاد میکند که با سیستم ماژول Node.js سازگار است. در Node.js، تابع Require برای بارگذاری فایلهای دیگر بهعنوان ماژول استفاده میشود.
در مرحله بعد، به فایل کامپایلشده src/vectors.ts که در out/vectors.js ذخیره شده است، نگاهی بیندازید:
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Vector3 = exports.Vector2 = void 0; var vector2_1 = require("./vector2"); Object.defineProperty(exports, "Vector2", { enumerable: true, get: function () { return vector2_1.Vector2; } }); var vector3_1 = require("./vector3"); Object.defineProperty(exports, "Vector3", { enumerable: true, get: function () { return vector3_1.Vector3; } });
در اینجا، کامپایلر TypeScript کدی سازگار با روش استفاده از ماژولها در CommonJS ایجاد کرده است که مقادیر صادرشده را به شیء Exports اختصاص میدهد.
در این بخش، با سینتکس TypeScript برای واردکردن (Import) و صادرکردن (Export) فایلها و نحوه کامپایلشدن آنها در جاوااسکریپت آشنا شدید.
استفاده از روش Default Exports
در این قسمت، روش دیگری برای صادرکردن یک مقدار از ماژولی به نام Default Exports را بررسی خواهیم کرد که تنها یک کد خاص را بهعنوان ماژول Exports میکند. استفاده از این روش میتواند کدها را هنگام واردکردن فایلها ساده کند.
فایل src/vector2.ts را دوباره باز کنید:
export class Vector2 { constructor(public x: number, public y: number) {} add(otherVector2: Vector2) { return new Vector2(this.x + otherVector2.x, this.y + otherVector2.y); } }
به روش صادرکردن ماژول با استفاده از Export دقت کنید. در اینجا، میتوانیم از روش Default Exports برای صادرکردن ماژول استفاده کنیم. دقت کنید هر فایل فقط میتواند یک Default Exports داشته باشد.
کد قبلی خود را به روش Default Exports صادر کنید:
export default class Vector2 { constructor(public x: number, public y: number) {} add(otherVector2: Vector2) { return new Vector2(this.x + otherVector2.x, this.y + otherVector2.y); } }
فایل را ذخیره کنید و همین کار را در فایل src/vector3.ts نیز انجام دهید:
export default class Vector3 { constructor(public x: number, public y: number, public z: number) {} add(otherVector3: Vector3) { return new Vector3( this.x + otherVector3.x, this.y + otherVector3.y, this.z + otherVector3.z ); } }
برای Importکردن Default Exports، فایلهای خود را ذخیره و فایل src/vectors.ts را باز کنید و محتوای آن را به موارد زیر تغییر دهید:
import Vector2 from "./vector2"; import Vector3 from "./vector3"; export { Vector2, Vector3 };
توجه کنید که برای هر دو نوع Export، میتوانید قبل از Importکردن آنها، نامی مستعار برایشان انتخاب کنید.
هر ماژولی که Default Exports دارد، بهمنظور Exportکردنش میتوانید از کلمه Default برای اشاره به مقدار Default Export آن استفاده و آن را نامگذاری کنید:
export { default as Vector2 } from "./vector2"; export { default as Vector3 } from "./vector3";
اکنون مقادیر Default Exports را با استفاده از نامی خاص صادر کردید.
استفاده از ” = export ” و ” ()import = require ” برای سازگاری
برخی از بارگذارکنندههای (Loaders) ماژول مانند AMD و CommonJS شیئی به نام Exports دارند که حاوی تمام مقادیر صادرشده ماژول است. هنگام استفاده از هریک از لودرهای ماژول، میتوان با تغییر مقدار شیء Exports، شیء صادرشده را بازنویسی کرد؛ تقریباً همانند اشیای موجود در خود TypeScript؛ بههمیندلیل، این دو ناسازگار هستند. در این بخش، به نحوه برخورد TypeScript با این ناسازگاری نگاهی خواهیم انداخت.
در TypeScript، هنگام استفاده از ماژول لودری که از بازنویسی شیء Exports پشتیبانی میکند، میتوانید مقدار شیء صادرشده را با استفاده از سینتکس ” = export ” تغییر دهید. اگر در گذشته از Node.js استفاده کردهاید، با این روش آشنا هستید.
توجه: قبل از انجام هریک از تغییرات زیر، مطمئن شوید که گزینه compilerOptions.module در فایل tsconfig.json روی CommonJS تنظیم شده است.
تصور کنید که میخواهید شیء صادرشده در هریک از فایلهای بردار را تغییر دهید تا به خود کلاس بردار اشاره کند. فایل src/vector2.ts را باز کنید و برای تغییر مقدار خود شیء صادرشده، مساوی را بعد از export قرار دهید:
export = class Vector2 { constructor(public x: number, public y: number) {} add(otherVector2: Vector2) { return new Vector2(this.x + otherVector2.x, this.y + otherVector2.y); } };
این فایل را ذخیره کنید و همین کار را در فایل src/vector3.ts نیز انجام دهید:
export = class Vector3 { constructor(public x: number, public y: number, public z: number) {} add(otherVector3: Vector3) { return new Vector3( this.x + otherVector3.x, this.y + otherVector3.y, this.z + otherVector3.z ); } };
درنهایت، فایل vectors.ts را بهصورت زیر تغییر دهید:
import Vector2 from "./vector2"; import Vector3 from "./vector3"; export { Vector2, Vector3 };
این فایلها را ذخیره و کامپایلر TypeScript را اجرا کنید:
npx tsc
کامپایلر TypeScript چندین خطا به شما میدهد:
Output src/vectors.ts:1:8 - error TS1259: Module '"~/project/src/vector2"' can only be default-imported using the 'esModuleInterop' flag 1 import Vector2 from "./vector2"; ~~~~~~~ src/vector2.ts:1:1 1 export = class Vector2 { ~~~~~~~~~~~~~~~~~~~~~~~~ 2 constructor(public x: number, public y: number) {} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ... 6 } ~~~ 7 } ~ This module is declared with using 'export =', and can only be used with a default import when using the 'esModuleInterop' flag. src/vectors.ts:2:8 - error TS1259: Module '"~/project/src/vector3"' can only be default-imported using the 'esModuleInterop' flag 2 import Vector3 from "./vector3"; ~~~~~~~ src/vector3.ts:1:1 1 export = class Vector3 { ~~~~~~~~~~~~~~~~~~~~~~~~ 2 constructor(public x: number, public y: number, public z: number) {} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ... 10 } ~~~ 11 } ~ This module is declared with using 'export =', and can only be used with a default import when using the 'esModuleInterop' flag.
این خطاها بهدلیل اشتباه واردکردن فایلهای بردار در src/vectors.ts است. این فایل هنوز از روش پیشفرض برای ورود و صدور ماژولها استفاده میکند؛ اما اکنون در حال بازنویسی شیء صادرشده هستید؛ بنابراین، دیگر صادرات پیشفرض ندارید. استفاده از هر دو روش باهم ناسازگار است.
دو راه برای حل این مشکل وجود دارد: یکی استفاده از ” ()import = require ” و دیگری تنظیم ویژگی esModuleInterop روی true در فایل پیکربندی TypeScript Compiler.
در ابتدا، در فایل src/vectors.ts سینتکس صحیح را برای واردکردن این نوع ماژول پیاده خواهیم کرد:
import Vector2 = require("./vector2"); import Vector3 = require("./vector3"); export { Vector2, Vector3 };
دستور ” ()import = require ” شیء Exports را بهعنوان مقدار به Import میدهد و به شما کمک میکند از هر کلاس بردار تعریفشده استفاده کنید. اکنون کد شما بدون خطا کامپایل خواهد شد.
روش دیگر برای حل خطای 1259 تنظیم گزینه compilerOptions.esModuleInterop روی true در فایل tsconfig.json است. وقتی این گزینه را فعال میکنید، کامپایلر TypeScript از کدهای خاصی برای بررسی شیء صادرشده استفاده میکند تا تشخیص دهد که آیا Exports پیشفرض است یا شیء Exports که بازنویسی شده. سپس آن را کامپایل میکند.
اگر از این کد استفاده کنید، دیگر به ویرایش فایل src/vectors.ts نیازی نیست و با همان کدهای قبلی نیز اجرا خواهد شد.
توجه: اگر از سیستم ماژول دیگری بهجز AMD و CommonJS استفاده کنید، کامپایلر TypeScript حین کامپایل به شما خطا میدهد.
بهعنوان مثال، اگر پیکربندی compilerOptions.module را روی ES6 تنظیم کنید تا سیستم از ماژول ES استفاده کند، کامپایلر TypeScript چندین خطا را به ما میدهد که تنها به دو خطای تکراری 1202 و 1203 خلاصه میشود:
"Output" src/vector2.ts:1:1 - error TS1203: Export assignment cannot be used when targeting ECMAScript modules. Consider using 'export default' or another module format instead. 1 export = class Vector2 { ~~~~~~~~~~~~~~~~~~~~~~~~ 2 constructor(public x: number, public y: number) {} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ... 6 } ~~~ 7 }; ~~ src/vectors.ts:1:1 - error TS1202: Import assignment cannot be used when targeting ECMAScript modules. Consider using 'import * as ns from "mod"', 'import {a} from "mod"', 'import d from "mod"', or another module format instead. 1 import Vector2 = require("./vector2");
جمعبندی
TypeScript سیستم ماژولی با ویژگیها و سینتکسی همانند ماژولهای ES ارائه میدهد. تایپاسکریپت به برنامهنویسان اجازه میدهد تا از انواع سیستمهای ماژول دیگر جاوااسکریپت مانند CommonJS ،AMD ،UMD ،SystemJS و ES6 استفاده کنند. با استفاده از گزینههای واردات و صادرات موجود در TypeScript، میتوانید مطمئن شوید که کد شما ماژولار و با اپلیکیشنهای جاوااسکریپتی بزرگ سازگار است. دانستن نحوه استفاده از ماژولها به شما امکان میدهد که کد برنامه خود را بهطور مختصر و کارآمد سازماندهی کنید؛ زیرا ماژولها بخشی اساسی از داشتن پایگاه کد ساختاریافتهای هستند که بهراحتی میتوان آنها را گسترش داد و نگهداری کرد.
سؤالات متداول
۱. TypeScript از چه سیستم ماژولی استفاده میکند؟
تایپاسکریپت از سیستم ماژول EcmaScript استفاده میکند.
۲. چگونه از ماژولها در TypeScript استفاده کنیم؟
با استفاده از کلمه کلیدی Import و Export میتوانید از ماژولها درون فایلهای دیگر استفاده کنید.
۳. چگونه در TypeScript ماژول ایجاد کنیم؟
هر فایلی که حاوی Import و Export باشد، ماژول در نظر گرفته میشود. برعکس، هر فایل بدون Import و Export بهعنوان اسکریپت تلقی میشود که محتویات آن در محدوده جهانی دردسترس قرار دارد و برای ماژولها نیز موجود است.
۴. چگونه کدهای خود را در TypeScript سازماندهی کنیم؟
TypeScript دو راه برای سازماندهی کد ارائه میدهد: Namespace نام و ماژولها.
۵. تفاوت ماژول و Namespace در TypeScript چیست؟
ماژول روشی است که برای سازماندهی کد در فایلهای جداگانه استفاده میشود و میتواند در محدوده محلی آنها اجرا شود، نه در دامنه جهانی؛ اما Namespace راهی است که برای گروهبندی منطقی عملکردها با محدوده محلی استفاده میشود.