شاید تا حالا عبارات compose و pipe رو شنیده باشید و این سوال در ذهنتون به وجود اومده باشد که این مفاهیم در برنامهنویسی به چه معنا هستن. Compose و Pipe از قدرتمندترین مفاهیم در برنامه نویسی تابعمحور یا functional programming در جاوا اسکریپت هستن. با این حال، درک اونها ممکنه برای بسیاری از برنامهنویسان به خصوص تازهکارها دشوار باشه. این مقاله فرصتیه برای آشنایی با این مفاهیم جالب و کاربردی در جاوااسکریپت.
اجازه بدین برای شروع و قبل از آشنایی با مفاهیم Compose و Pipe، کمی درباره برنامهنویسی تابعی صحبت کنیم.
برنامهنویسی تابعی
در برنامهنویسی، پارادایم (paradigm) یا الگوهای متنوعی وجود دارند که ممکنه با برخی از اونها آشنا باشید:
- برنامه نویسی دستوری (imperactive programming)
- برنامهنویسی پروسهای (Procedural programming)
- برنامهنویسی شئگرا (object oriented programming, OOP)
- رویکرد پردازش موازی (Parallel processing Approach)
- برنامه نویسی اعلانی یا اخباری (declarative programming)
- برنامهنویسی منطقی (logical programming)
- برنامه نویسی تابعمحور (functional programming)
- برنامهنویسی واکنشگرا (reactive programming)
برنامهنویسی تابعی یک شیوه کدنویسی و به بیان ساده به این معنیه که با استفاده از توابع خالص، (pure functions) عملیات بزرگ و پیچیده رو به مجموعهای از توابع کوچکتر و ساده تر تبدیل کنیم و بهجای استفاده از کدنویسی عادی که شامل استفاده از شرطها، حلقهها و... هست، از فراخوانی توابع برای اجرای برنامه استفاده کنیم. این شیوه در مقایسه با برنامهنویسی شئگرا مختصرتر و قابل پیشبینیتره و تست کردن اون هم آسونتر هست.
خب برگردیم به بحث اصلیمون! همونطور که اشاره کردم، Compose و Pipe دوتا از مفاهیم کاربردی و جالب در برنامهنویسی تابعی هستن.
آشنایی با مفهوم Compose
ترکیب (compose) توابع، ساختاری هست که به وسیلهی اون با ترکیب چندین تابع ساده یک تابع پیچیدهتر میسازیم و خروجی هر تابع به تابع بعدی منتقل میشه. ما قبلا هم با ترکیب توابع کار کردیم! در درس ریاضیات ترکیب توابع این امکان رو به ما میده که یک تابع رو در خروجی یک تابع دیگر اعمال کنیم یا به زبان دیگه، خروجی یک تابع، ورودی تابع بعدی باشه:
![](https://sokanacademy.s3.ir-thr-at1.arvanstorage.ir/8636/conversions/image-default.webp)
در این مثال خروجی تابع f با ورودی x ، ورودی تابع g هست.
همونطور که میبینیم، ترکیب توابع از راست به چپ کار میکنه (از راست به چپ توابع به ترتیب اجرا میشن و خروجی اون ها، ورودی تابع بعدی در سمت چپشون میشه).
بیاین یه مثال بهتر ببینیم؛
فرض کنید یک اسم (رشته) داریم که اول میخواهیم تمام حروفش رو به حروف کوچک (lower case) تبدیل کنیم، بعد اون رو تریم کنیم (فاصلهها مثل space رو حذف کنیم)، سپس اون رو درون یک تگ h1 قرار بدیم.
let myName = " John ";
let lowerCase = myName.toLowerCase();
let output = "<h1>" + lowerCase.trim() + "</h1>";
بد نیست! کار هم میکنه، اما این یک شیوهی غیرتابعی کدنویسی هست و اگر تعداد خطوط کد زیاد باشن عیب یابی اون دشواره. بین خودمون بمونه، روش حرفهای هم نیست!
بیاین این مشکل رو به وسیله تکنیکهای برنامهنویسی تابعی حل کنیم:
let myName = " John ";
let trim = str => str.trim();
let stringToLowerCase = str => str.toLowerCase();
let wrapString = str => `<h1> ${str} </h1>`;
const result = wrapString( stringToLowerCase( trim( myName ) ) );
در قطعه کد بالا برای هر کدوم از اعمالی که میخوایم انجام بدیم یک تابع جداگانه تعریف کردیم. در آخرین خط، از ترکیب توابع یا همون composing functions استفاده کردیم (همونطور که بالاتر گفتیم، ترتیب اجرای توابع از راست به چپه).
اما این تابع دوتا مشکل داره: اول اینکه برای درک نحوه کار تابع، باید اون رو از راست به چپ بخونیم که ممکنه سخت باشه (چون عادت داریم انگلیسی رو از چپ به راست بخونیم)؛ مشکل دوم وجود پرانتزهاست که اگه تعداد توابع ما زیاد باشه ظاهر کد زشت و درک اون سخت خواهد بود.
برای حل این دو مشکل باید به سراغ یک کتابخانه جاوااسکریپت به نام “Lodash” بریم و با استفاده از اون کدی که نوشتیم رو ساده کنیم. این کتابخانه محبوب و کارآمد همچنین پکیجی پر از توابع از پیش ساخته شده برای برنامهنویسی تابعی داره. جالب به نظر میرسه نه؟ پس بریم سراغش...
برای استفاده از اون اول باید نصبش کنیم. برای این کار در پنجره ترمینال به مسیر پروژه مورد نظرمون میریم و دستور زیر رو در اون اجرا میکنیم:
توجه: قبل از اجرای دستور باید npm رو نصب کرده باشیم. اگر با npm آشنایی ندارین میتونید دوره آموزشی npm که در سکان آکادمی منتشر شده رو از اینجا مطالعه کنید.
npm i lodash
بعد از اینکه lodash نصب شد درون پروژه بهش دسترسی داریم. حالا باید دو تابع مورد نیازمون رو از اون import کنیم. دو تابع مورد نیازمون Pipe و Compose هستن.
import { compose, pipe } from "lodash/fp";
شاید براتون سوال شده باشه که عبارت “fp” که در ادامهی lodash اومده به چه معناست. اون حروف مخفف functional programming هستن؛ این یعنی به توابعی که مربوط به functional programming هستن از پکیج lodash نیاز داریم و فقط اونها رو import میکنیم.
خب برگردیم به کد خودمون؛ وقتشه کدمون رو با استفاده از این توابع بازنویسی کنیم.
// const result = wrapString( stringToLowerCase( trim( myName ) ) );
const transform = compose(wrapString, stringToLowerCase, trim);
transform( myName );
دقت کنید که ما توابع رو فراخوانی نکردیم، فقط یک reference از اونها رو ارسال کردیم.
Compose همچنین یک مثال از “higher order functions” هست چون تعدادی تابع به عنوان ورودی دریافت میکنه و یک تابع برمیگردونه که ترکیب همهی اون توابع هست.
همونطور که میبینید دیگه خبری از پرانتزها نیست و کدمون تمیزتر شده. اما هنوز یک مشکل کوچیک وجود داره و اون اینکه برای درک نحوه کار تابع باید ورودی های اون رو از راست به چپ بخونیم. آیا میشه این مشکل رو حل کرد تا خوانایی کد بالاتر بره؟ اینجاست که pipe وارد عمل میشه.
آشنایی با مفهوم Pipe
Pipe به معنی لوله یا لولهکشی هست. مفهوم سادهای هم داره، به این صورت کارمیکنه که n تابع رو میگیره و ترکیب میکنه. مانند جریان درون یک لوله هر تابع رو با خروجی تابع قبل فراخوانی میکنه، اما از چپ به راست.
const transform = pipe(trim, stringToLowerCase, wrapString);
transform(myName);
توابع رو به همون ترتیبی که میخواهیم اجرا بشن به عنوان ورودی به تابع میفرستیم (دوباره قابل ذکره که توابع رو فراخوانی نمیکنیم) و تمام! به همین سادگی دیگه خبری از پرانتز های زیاد نیست و کد خوانایی بیشتری پیدا کرده.
خب اینم از دوتا تابع کاربردی و جالب در جاوااسکریپت. امیدوارم براتون مفید بوده باشه.