bind در جاوا اسکریپت چیست؟ – از کاربرد تا نحوه استفاده

۴۴۴ بازدید
آخرین به‌روزرسانی: ۳۰ خرداد ۱۴۰۲
زمان مطالعه: ۹ دقیقه
bind در جاوا اسکریپت چیست؟ – از کاربرد تا نحوه استفاده

جاوا اسکریپت به عنوان یکی از بهترین زبان‌های برنامه نویسی، حاوی توابع و متدهای بسیار زیادی است که می‌توان از آن‌ها برای انجام کارهای خاص و کاربردی استفاده کرد. یکی از این متدهای پرکاربرد، متد «bind» است. متد bind در جاوا اسکریپت برای ایجاد تابعی جدید با «زمینه‌ای» (Context) خاص استفاده می‌شود که معمولاً به آن تابع «binding» می‌گویند. این تابع به کاربر اجازه می‌دهد تا مقدار This در جاوا اسکریپت را به صراحت در تابع ایجاد شده جدید تنظیم کند. در این مطلب از «مجله فرادرس» می‌خواهیم در رابطه با متد bind در جاوا اسکریپت و رسالت آن به همراه ارائه چندین مثال کاربردی توضیحاتی را ارائه کنیم. کاربران با مطالعه این مطلب درک مطلوبی از bind در زبان برنامه نویسی جاوا اسکریپت پیدا خواهند کرد.

bind در جاوا اسکریپت چیست؟

متد bind در جاوا اسکریپت تابع جدیدی را برمی‌گرداند که در زمان فراخوانی، مقدار This روی مقدار ارائه شده خاصی تنظیم خواهد شد. این امر به کاربر امکان می‌دهد تا نسخه‌ای تغییر یافته از تابع را با زمینه‌ای ثابت برای This ایجاد کند.

«سینتکس» (Syntax) متد bind در ‌Javascript به صورت زیر است:

1fn.bind(thisArg[, arg1[, arg2[, ...]]])

در سینتکس بالا، متد‎ bind()  تابعی جدید ایجاد می‌کند که نوعی کپی از تابع اصلی fn  محسوب می‌شود. تابع جدید دارای مقدار This خاص ( thisArg  ) است و همچنین می‌تواند آرگومان‌های اضافی ( arg1  ، arg2   و غیره) را بپذیرد. توجه به این نکته مهم است که بر خلاف متدهای call()‎  و application()  ‎، متد bind در جاوا اسکریپت بلافاصله تابع را اجرا نمی‌کند. در عوض، نسخه جدیدی از تابع را با مقدار This بر روی آرگومان ارائه شده thisArg بازمی‌گرداند. این به کاربر امکان می‌دهد تا تابع محدود شده را بعداً ذخیره و استفاده کند یا آن را به عنوان نوعی تماس ارسال کند، بدون اینکه زمینه This مورد نظر را از دست بدهد.

مثالی برای درک bind در جاوا اسکریپت

فرض می‌شود که ۲ شخص به نام‌های alice  و bob  هر کدام سبد میوه دارند که در داخل سبد alice پرتقال و در داخل سبد bob انگور وجود دارد.

همچنین سبد میوه bob در داخل سبد میوه alice مانند شکل زیر قرار گرفته است.

درک Bind در جاوا اسکریپت

در جاوا اسکریپت، This به شیئی اشاره می‌کند که تابع فعلی در حال فراخوانی آن است. بنابراین، وقتی alice تابعی را برای دریافت میوه از سبد خود فراخوانی می‌کند، به This به عنوان سبد خودش اشاره خواهد کرد که حاوی پرتقال است. قطعه کد زیر برای بیان این مفهوم آورده شده است.

1var alice = {
2  fruit: "orange",
3  getFruit: function() {
4    return this.fruit;
5  }
6};
7
8alice.getFruit(); // "orange"

حال، اگر bob بخواهد تابع getFruit  را فراخوانی کند، کار نخواهد کرد، زیرا تابع نام برده نوعی ویژگی سبد او نیست. در عوض، bob خطایی دریافت می‌کند، زیرا تابع getFruit در سبد او وجود ندارد.

1var bob = {
2  fruit: "grape",
3  basket: {
4    getFruit: function() {
5      return this.fruit;
6    }
7  }
8};
9
10bob.basket.getFruit(); // Error: Cannot read property 'fruit' of undefined

برای حل این مشکل می‌توان از تابع bind استفاده کرد. bind به کاربر اجازه می‌دهد که مقدار This را به صراحت تعیین کند. در این حالت، bob می‌خواهد تابع را به سبد خود متصل کند تا به سبدش اشاره کند، نه شی سراسری که برای درک بهتر، کدهای زیر ارائه شده‌اند.

1var bob = {
2  fruit: "grape",
3  basket: {
4    getFruit: function() {
5      return this.fruit;
6    }
7  }
8};
9
10var getBobFruit = bob.basket.getFruit.bind(bob);
11getBobFruit(); // "grape"

با استفاده از bind در جاوا اسکریپت، باب اکنون می‌تواند تابع getFruit را فراخوانی و نتیجه صحیح را دریافت کند، زیرا این تابع اکنون به سبد او اشاره دارد.

متد bind در جاوا اسکریپت برای اتصال تابع

در جاوا اسکریپت، زمانی که متد شیئی را به عنوان نوعی فراخوانی به تابع دیگری ارسال می‌کند، زمینه This امکان دارد از بین برود یا تغییر کند.

مثال زیر برای درک این مفهوم آورده شده است:

1let person = {
2    name: 'John Doe',
3    getName: function() {
4        console.log(this.name);
5    }
6};
7
8setTimeout(person.getName, 1000);

خروجی کد بالا به جای John Doe  ، «تعریف نشده» ( undefined  ) خواهد بود. این اتفاق به این دلیل رخ خواهد داد که setTimeout()‎  تابع، person.getName  را به طور جداگانه از شی person  دریافت می‌کند. برای رفع این مشکل، چند راه‌حل وجود دارد. روش اول این است که تماس با person.getName را در «تابعی ناشناس» (Anonymous Function) به صورت زیر قرار دهیم:

1setTimeout(function () {
2    person.getName();
3}, 1000);

کد بالا بدون هیچ مشکل خاصی کار می‌کند، زیرا تابع ناشناس، شی person را از محدوده بیرونی می‌گیرد و سپس متد getName()‎  را روی آن فراخوانی می‌کند. راه‌حل دیگر این مسئله، استفاده از متد bind در جاوا اسکریپت به صورت زیر است:

1let f = person.getName.bind(person);
2setTimeout(f, 1000);

در کد فوق از متد bind() برای اتصال متد person.getName  به شی person استفاده شده است. رویکرد بالا تابع جدید f  را ایجاد می‌کند که در آن مقدار This به طور صریح برای شی person تنظیم شده است. سپس f به‌ عنوان پاسخ تماس به setTimeout()  فرستاده خواهد شد و اطمینان حاصل می‌شود که متد getName()‎ با زمینه صحیح فراخوانی شده است. هر دوی این رویکردها به کاربر این امکان را می‌دهند که هنگام استفاده از متد شی به عنوان فراخوانی در جاوا اسکریپت، زمینه This مورد نظر را حفظ کند.

متد بیند در جاوا اسکریپت

استفاده از bind برای قرض گرفتن متدها از شیئی متفاوت

در جاوا اسکریپت، می‌توان از متد bind() برای قرض گرفتن متدی از شی و تنظیم زمینه This بر روی شیئی دیگر استفاده کرد.

برای نشان دادن این موضوع، فرض می‌کنیم شی runner  با متد run()  به صورت زیر در دسترس است.

1let runner = {
2    name: 'Runner',
3    run: function(speed) {
4        console.log(this.name + ' runs at ' + speed + ' mph.');
5    }
6};

همچنین شی flyer با متد fly()  به صورت زیر موجود است:

1let flyer = {
2    name: 'Flyer',
3    fly: function(speed) {
4        console.log(this.name + ' flies at ' + speed + ' mph.');
5    }
6};

برای اینکه شی flyer  بتواند با استفاده از متد run() اجرا شود، می‌توان از متد bind در جاوا اسکریپت برای ایجاد تابعی جدید با مقدار This برای شی flyer به صورت زیر استفاده کرد:

1let run = runner.run.bind(flyer, 20);
2run();

در کد فوق، متد bind() در متد runner.run()  فراخوانی شده و شی flyer به عنوان آرگومان اول و مقدار 20  به عنوان آرگومان دوم ارسال شده است. این کار تابعی جدید را اجرا می‌کند که به شی flyer متصل بوده و آرگومان 20 نیز از پیش تنظیم شده است. در نهایت، تابع run() فراخوانی خواهد شد که خروجی را ثبت می‌کند و این خروجی به صورت زیر است:

Flyer runs at 20 mph

با استفاده از bind() ، می‌توان متد run() را از شی runner قرض گرفت و زمینه This را بدون ایجاد نوعی کپی جداگانه از متد، روی شی flyer تنظیم کرد. این به شی flyer اجازه می‌دهد تا از متد run() به گونه‌ای استفاده کند که انگار مال خودش است. این توانایی برای قرض گرفتن متدها بین اشیا با استفاده از bind() نوعی ویژگی قدرتمند در جاوا اسکریپت است، زیرا استفاده مجدد از کدها را ترویج کرده و از تکرار پیاده‌سازی متد جلوگیری می‌کند.

انواع رویکرد bind در جاوا اسکریپت

تابع bind در Javascript امکان سفارشی‌سازی رفتار و استفاده از توابع جاوا اسکریپت را با ایجاد نوعی زمینه خاص فراهم می‌کند.

در کل ۲ نوع رویکرد برای استفاده از bind در زبان برنامه نویسی جاوا اسکریپت وجود دارد که این ۲ نوع رویکرد به صوت زیر هستند.

در ادامه هر ۲ رویکرد نام برده شده مورد بررسی قرار گرفته‌اند.

اتصال اشیا در جاوا اسکریپت با متد bind

زمانی که کاربر بخواهد تابع برای نمونه‌ای خاص از کلاس کار خاصی را انجام دهد و بدون استفاده از آن نمونه قابل فراخوانی باشد، می‌تواند از متد bind در جاوا اسکریپت برای ایجاد نوعی کپی تغییر یافته از آن تابع استفاده کند. متد bind() به کاربر امکان می‌دهد تابع را به شیئی خاص متصل کنیم که در آن کلمه کلیدی This در تابع کپی شده، به شی محدود شده اشاره می‌کند.

مثال زیر برای درک این مفهوم بسیار مهم است.

1class Person {
2  constructor(name, age) {
3    this.name = name;
4    this.age = age;
5  }
6}
7
8Person.prototype.printName = function() {
9  console.log(this.name + ' ' + this.age);
10}
11
12var katy = new Person("Katy", 25);
13
14var printKaty = Person.prototype.printName.bind(katy);
15printKaty();

تصویر زیر نحوه انجام عملیات کد فوق را نشان می‌دهد.

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

در مثال فوق، کلاس Person  با متد printName()  موجود هستند. برای چاپ اطلاعات خاص، برای مثال Katy  ، بدون نوشتن تابعی جدید، می‌توان از متد bind() استفاده کرد. با ارسال شی Katy (که نمونه‌ای از کلاس Person است) به عنوان اولین آرگومان برای bind() ، نوعی کپی تغییر یافته از متد printName() ایجاد می‌شود که به شی Katy محدود شده است. کلمه کلیدی this  در تابع printKaty  اکنون به شی Katy اشاره دارد.

با فراخوانی printKaty ، کپی اصلاح شده متد printName() اجرا می‌شود و خروجی Katy 25  را در کنسول ثبت می‌کند. این کار به کاربر اجازه می‌دهد تا نوعی تابع ( printKaty ) ایجاد کند که به طور خاص به نوعی شی ( Katy ) متصل است و می‌تواند مستقل از آن شی فراخوانی شود، در حالی که همچنان به ویژگی‌ها و متدهای آن دسترسی وجود دارد.

اتصال پارامتر با متد bind در جاوا اسکریپت

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

مثال زیر برای بیان این موضوع آورده شده است.

1function multiply(a, b){
2  return a * b;
3}
4
5var double = multiply.bind(this, 2);
6console.log(double(3));

تصویر زیر نحوه انجام عملیات مثال بالا را نشان می‌دهد:

متد bind در جاوا اسکریپت

در مثال فوق، تابع multiply()  موجود است که ۲ عدد را در یکدیگر ضرب خواهد کرد. برای ایجاد تابع جدید double(x) که همیشه x  را در 2  ضرب می‌کند، بدون اینکه صریحاً اعلان شود، می‌توان از متد bind در جاوا اسکریپت استفاده کرد.

با فراخوانی multiply.bind(this, 2)  ، مقدار 2 به اولین آرگومان تابع multiply()  متصل می‌شود. این نوعی تابع جدید به نام double  ایجاد می‌کند که در آن آرگومان اول به صورت مقدار 2 ثابت می‌شود. همچنین هنگامی که double(3)  فراخوانی شود، آرگومان باقی‌مانده 3  به تابع double ارسال خواهد شد. در داخل، 2 (آگومان محدود شده) در 3 ضرب می‌شود و نتیجه 6  در کنسول چاپ خواهد شد.

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

توابع جزئی چه هستند؟

«توابع جزئی» (Partial Functions) در جاوا اسکریپت به کاربر این امکان را می‌دهند تا نه تنها زمینه This، بلکه برخی از آرگومان‌های تابع را نیز متصل کند. این کاربرد می‌تواند در برخی از سناریوها مفید باشد.

تابع bind در جاوا اسکریپت سینتکس کاملی را برای ایجاد تابع جزئی به صورت زیر فراهم می‌کند.

1let bound = func.bind(context, [arg1], [arg2], ...);

با استفاده از bind() ، می‌توان زمینه را به صورت This پیوند داد و همچنین آرگومان‌های شروع را برای تابع ارائه کرد. برای این مفهوم، مثالی از ضرب ۲ عدد به صورت زیر آورده شده است:

1function mul(a, b) {
2  return a * b;
3}

می‌توان تابعی جدید به نام double را بر اساس mul  با استفاده از bind() به صورت زیر استفاده کرد.

1function mul(a, b) {
2  return a * b;
3}
4
5let double = mul.bind(null, 2);
6
7alert( double(3) ); // = mul(2, 3) = 6
8alert( double(4) ); // = mul(2, 4) = 8
9alert( double(5) ); // = mul(2, 5) = 10

در مثال فوق، mul.bind(null, 2)  تابع دوگانه‌ای ایجاد خواهد کرد که mul را فراخوانی می‌کند، null  به عنوان زمینه و مقدار ۲ به عنوان اولین آرگومان ارسال می‌شوند. هر آرگومان دیگری که به double ارسال شود، مستقیماً به mul ارسال خواهد شد. به این تکنیک، کاربرد تابع جزئی می‌گویند که در آن کاربر تابعی جدید را با ثابت کردن برخی از پارامترهای موجود ایجاد می‌کند.

توابع جزئی در جاوا اسکریپت

توجه به این نکته، مهم است که در مثال‌های بالا، در واقع از This استفاده نشده است، ولی با این حال از آنجایی که bind() به این آرگومان نیاز دارد، می‌توان از چیزی مانند null استفاده کرد.

کاربرد تابع جزئی در جاوا اسکریپت چیست؟

کاربرد تابع جزئی به ویژه زمانی مفید است که کاربر نوعی تابع عمومی دارد و برای ایجاد توابع تخصصی در شی یا ماژول به آن تکیه خواهد کرد. به طور کلی، توابع جزئی با اجازه دادن به کاربر برای ایجاد توابع جدید با آرگومان‌های از پیش تعیین شده و در عین حال دست نخورده نگه‌داشتن تابع اصلی، انعطاف و راحتی را ارائه می‌دهند.

استفاده از توابع جزئی بدون زمینه

اگر کاربری بخواهد آرگومان‌های خاصی را از تابع بدون اتصال به this context  یا زمینه This تصحیح کند، متد bind در جاوا اسکریپت به او این امکان را نخواهد داد که مستقیماً این کار را انجام دهد. با این حال، به راحتی می‌توان تابع جزئی سفارشی را پیاده سازی کرد که فقط آرگومان‌ها را متصل می‌کند. در پایین مثالی از اجرای تابع جزئی با چنین رویکردی آورده شده است:

1function partial(func, ...argsBound) {
2  return function(...args) { // (*)
3    return func.call(this, ...argsBound, ...args);
4  }
5}

در کد بالا تابع جزئی نوعی پارامتر func  را می‌گیرد که نشان دهنده تابعی است که باید اعمال شود. argsBound  هم آرگومان‌هایی را نشان می‌دهد که باید محدود شوند. تابع func ، تابع wrapper (*)‎  را بازمی‌گرداند که هنگام فراخوانی، تابع را با موارد زیر فراخوانی می‌کند.

  • مقداری که دریافت می‌کند (به عنوان مثال، user  در مورد user.sayNow  )
  • آرگومان‌های argsBound  از فراخوانی جزئی، مانند 10:00  .
  • آرگومان‌های args  ارائه شده به wrapper  ، مانند Hello  .

این به کاربر اجازه می‌دهد تا آرگومان‌های خاصی از تابع ثابت شوند و این در حالی است که زمینه This دست نخورده باقی می‌ماند. به عنوان مثال، شی user را با متد say  به صورت زیر در نظر می‌گیریم:

1let user = {
2  firstName: "John",
3  say(time, phrase) {
4    alert(`[${time}] ${this.firstName}: ${phrase}!`);
5  }
6};

می‌توان با استفاده از تابع جزئی نوعی متد جزئی مانند sayNow  را با زمان ثابت به کدها به صورت زیر اضافه کرد:

1user.sayNow = partial(user.say, new Date().getHours() + ':' + new Date().getMinutes());
2
3user.sayNow("Hello");
4// Output: [10:00] John: Hello!

در مثال فوق، user.sayNow  تابعی است که با استفاده از partial(user.say، new Date().getHours() + ':' + new Date().getMinutes())  ایجاد شده است که متد say  را به user  متصل می‌کند. در کدهای فوق همچنین بخش Date  بر اساس زمان فعلی هنگامی که user.sayNow  فراخوانی می‌شود پیام Hello را با زمان ثابت و عبارت ارائه شده نمایش می‌دهد. با استفاده از تابع جزئی، می‌توان به راحتی توابعی را با آرگومان‌های از پیش تنظیم شده ایجاد کرد که به انعطاف‌پذیری و قابلیت استفاده مجدد بیشتر می‌انجامد.

نکته: باید به این نکته توجه داشت که اجرای جزئی تابع نشان داده شده در مثال فوق ساده شده است و همه موارد استفاده ممکن را پوشش نمی‌دهد. همچنین کتابخانه‌هایی مانند «lodash» یا «Ramda» وجود دارند که اجرای جامع تری از کاربرد تابع جزئی و ترکیب تابع را ارائه می‌دهند که بحث در مورد آن‌ها خارج از محدوده این نوشته است.

سخن پایانی

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

علاوه بر این، bind() کار با توابع جزئی را امکان‌پذیر می‌کند و به کاربر اجازه می‌دهد توابع تخصصی را با برخی از آرگومان‌های از پیش تنظیم شده ایجاد کند. این کار به بهبود قابلیت استفاده مجدد و خوانایی کدها با اجتناب از آرگومان‌های تکراری کمک می‌کند. به طور کلی، bind() انعطاف‌پذیری را در مدیریت آرگومان‌ها و توابع فراهم می‌کند و تطبیق‌پذیری توابع جاوا اسکریپت را افزایش می‌دهد. در مطلب فوق از «مجله فرادرس» متد bind در جاوا اسکریپت به همراه کاربردهای آن به صورت عملی آموزش داده شد و در رویکردهای مختلف استفاده از این متد مورد بررسی قرار گرفت.

بر اساس رای ۲ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
JavascriptTutorialEducativeJavascriptZeninVader
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *