«بستار» یک الگوی برنامهنویسی در JavaScript است که اجازه میدهد از متغیرهای یک دامنهی واژگانی بیرونی درون یک «بلوک کد» تودرتو استفاده شود. JavaScript از بستارها بهصورت شفاف پشتیبانی میکند و اغلب بدون آنکه بدانیم چیستند از آنها استفاده میشود.
// Top-level declarations are global-scope
const dozen = 12;
// Functions create a new function-scope and block-scope.
// Referencing the outer variable here is a closure.
function nDozen(n) {
return dozen * n;
}
نام بستار از نظر تاریخی از λ-calculus گرفته شده و scheme آن را رواج داده است (منبع) تا به اتصالهای متغیرِ باز و بستهی یک تابع اشاره کند.
حریم خصوصی دادهها / کپسولهسازی دادهها
// Consider this function:
const saveNumber = (number) => {
// The saved value is unaccessible by the outer lexical scope.
const value = number;
// We can provide access to the primitive value with a function, but the original will never change
return () => value;
};
// Attempting to set the variable outside of its lexical scope results in an error
value = 42;
اعمال جزئی
// The arguments are applied one-by-one, using closures to arrive at the final result
function partialBuildUri(scheme) {
return function (domain) {
return function (path) {
return `${scheme}://${domain}/${path}`;
};
};
}
// A function could apply them all at once.
function buildUri(scheme, domain, path) {
return partialBuildUri(scheme)(domain)(path);
}
// Or apply a few to create a flexible system of functions for reuse.
function buildHttpsExercismUri(path) {
return partialBuildUri('https')('exercism.org');
}
در هر زبان برنامهنویسی، بستارها ارتباط نزدیکی با دامنهی متغیرها دارند. در JavaScript سه نوع دامنهی واژگانی برای متغیرها وجود دارد:
var اعلام میشوند.{...}) با کلیدواژههای let و const اعلام میشوند.در عمل، بستار اغلب زمانی رخ میدهد که یک تابع (یا بلوک) از متغیری در دامنهی بیرونی استفاده کند. در JavaScript این کار بهصورت شفاف پشتیبانی میشود، به همین دلیل اغلب بستارها بدون اشارهی مشخص به کار میروند.
کلیدواژهی var یک متغیر با دامنهی تابع تعریف میکند. یعنی متغیرهایی که با var تعریف میشوند، در هر جای تابعی که در آن تعریف شدهاند و در هر دامنهی واژگانی تودرتوی دیگری (چه تابع و چه بلوک) در دسترس هستند.
{
var five = 5;
}
// This will succeed because 'five' exists in the same scope
var tenTimes = five * 10;
کلیدواژههای let و const متغیرهایی با دامنهی بلوک تعریف میکنند. let یک متغیر تغییرپذیر تعریف میکند که مقدارش ممکن است چندین بار تنظیم شود و ممکن است تعریف شود ولی مقداردهی اولیه نشود. const متغیری تعریف میکند که هنگام تعریف باید مقداردهی اولیه شود و پس از آن مقدارش نمیتواند تغییر کند. اگر متغیر const به یک مقدار ابتدایی مقداردهی شود، نمیتوان آن را تغییر داد. اگر متغیر const به یک مقدار ارجاعی، مانند یک آرایه یا شیء، مقداردهی شود، خود ارجاع نمیتواند تغییر کند اما میتوان محتویات آرایه را تغییر داد.
این بلوک را در نظر بگیرید:
// 'two' is defined at the top-level, therefore available to the global-scope
const two = 2;
{
// This succeeds, as 'two' is available from the outer lexical scope
const oneLess = two - 1;
}
// This throws an error because oneLess is not defined outside of the previous inner lexical scope
console.log(oneLess);
هرچند میتوانیم از آکولادها ({...}) بهصورت دلخواه برای ساختن بلوک استفاده کنیم، بیشتر اوقات آنها را پیرامون دستورهای شرطی، توابع و کلاسها میبینیم.
const PI = 3.14;
// This function uses a closure for the value of PI (π)
function areaOfCircle(radius) {
return PI * radius * radius;
}