از طریق منوی جستجو مطلب مورد نظر خود در وبلاگ را به سرعت پیدا کنید
معرفی پراکسی های جاوا اسکریپت در ES6 در این مقاله قصد داریم در مورد پراکسی های جاوا اسکریپت که با نسخه جاوا اسکریپت ECMAScript 6 (ES6) معرفی شده اند صحبت کنیم. ما از برخی از نحو ES6 موجود، از جمله عملگر spread در این مقاله استفاده خواهیم کرد. بنابراین اگر دانش اولیه ای در مورد ES6 داشته باشید مفید خواهد بود. چی…
سرفصلهای مطلب
معرفی
در این مقاله قصد داریم در مورد پروکسی های جاوا اسکریپت که با نسخه جاوا اسکریپت معرفی شدند ECMAScript 6 (ES6). ما از برخی از نحو ES6 موجود، از جمله عملگر spread در این مقاله استفاده خواهیم کرد. بنابراین اگر دانش اولیه ای در مورد ES6 داشته باشید مفید خواهد بود.
پروکسی چیست؟
پراکسی های جاوا اسکریپت توانایی تغییر رفتار اساسی اشیا و توابع را دارند. ما میتوانیم زبان را طوری گسترش دهیم که با نیازهای ما مطابقت داشته باشد یا به سادگی از آن برای مواردی مانند اعتبارسنجی و کنترل دسترسی استفاده کنیم روی یک ملک
تا زمانی که پراکسی ها معرفی نشدند، ما دسترسی سطح بومی برای تغییر رفتار اساسی یک شی یا یک تابع نداشتیم. اما با آنها ما این توانایی را داریم که به عنوان یک لایه میانی عمل کنیم، روش دسترسی به شی را تغییر دهیم، اطلاعاتی مانند تعداد دفعات فراخوانی یک تابع و غیره را تولید کنیم.
مثال پروکسی املاک
بیایید با یک مثال ساده شروع کنیم تا پروکسی ها را در عمل ببینیم. برای شروع، بیایید یک شی شخص با آن ایجاد کنیم firstName
، lastName
، و age
خواص:
const person = {
firstName: 'John',
lastName: 'Doe',
age: 21
};
حالا بیایید یک پروکسی ساده با ارسال آن به آن ایجاد کنیم Proxy
سازنده پارامترهایی به نام the را می پذیرد target
و handler
. هر دوی این موارد به زودی توضیح داده خواهد شد.
بیایید ابتدا یک شی handler ایجاد کنیم:
const handler = {
get(target, property) {
console.log(`you have read the property ${property}`);
return target(property);
}
};
به این صورت می توانید یک پروکسی ساده ایجاد کنید:
const proxyPerson = new Proxy(person, handler);
console.log(proxyPerson.firstName);
console.log(proxyPerson.lastName);
console.log(proxyPerson.age);
اجرای این کد باید نتیجه دهد:
you have read the property firstName
John
you have read the property lastName
Doe
you have read the property age
21
هر بار که به یک ویژگی از آن شیء پراکسی دسترسی پیدا می کنید، یک علامت دریافت خواهید کرد console پیام با نام ملک این یک مثال بسیار ساده از یک پروکسی جاوا اسکریپت است. بنابراین با استفاده از آن مثال، اجازه دهید با چند اصطلاح آشنا شویم.
هدف پروکسی
پارامتر اول، target
، شیئی است که شما پروکسی را به آن متصل کرده اید. این شی توسط پروکسی برای ذخیره داده ها استفاده می شود، به این معنی که اگر مقدار شی هدف را تغییر دهید، مقدار شی پراکسی نیز تغییر می کند.
اگر می خواهید از این امر جلوگیری کنید، می توانید از آن عبور کنید هدف به طور مستقیم به پروکسی به عنوان یک شی ناشناس، یا میتوانید از روش کپسولهسازی برای محافظت از شی اصلی با ایجاد یک عبارت تابع فراخوانی فوری (IIFE) یا تکتن استفاده کنید.
فقط شی خود را در معرض خارج قرار ندهید که در آن از پروکسی استفاده می شود و همه چیز باید خوب باشد.
تغییر در شی هدف اصلی همچنان در پروکسی منعکس می شود:
console.log(proxyPerson.age);
person.age = 20;
console.log(proxyPerson.age);
you have read the property age
21
you have read the property age
20
کنترل کننده پروکسی
پارامتر دوم به Proxy
سازنده است handler
، که باید یک شی حاوی متدهایی باشد که روشی را که می خواهید کنترل کنید را توصیف می کند target
رفتار روش های داخل این هندلر، به عنوان مثال get()
روش، نامیده می شوند تله ها.
با تعریف یک handler، مانند چیزی که در مثال قبلی خود تعریف کردیم، میتوانیم منطق سفارشی را برای یک شی بنویسیم که در غیر این صورت آن را پیادهسازی نمیکند.
به عنوان مثال، می توانید یک پروکسی ایجاد کنید که حافظه پنهان یا پایگاه داده را هر زمان که یک ویژگی به روز می کند، به روز می کند روی شی مورد نظر به روز می شود.
تله های پروکسی
را گرفتن() دام
را get()
هنگامی که شخصی سعی می کند به یک ملک خاص دسترسی پیدا کند، تله آتش می گیرد. در مثال قبلی از این استفاده کردیم print یک جمله در هنگام دسترسی به ملک.
همانطور که قبلاً می دانید، جاوا اسکریپت از ویژگی های خصوصی پشتیبانی نمی کند. بنابراین گاهی اوقات به عنوان یک قرارداد، توسعه دهندگان از خط زیر (_
) در مقابل نام ملک، به عنوان مثال، _securityNumber
، برای شناسایی آن به عنوان یک ملک خصوصی.
با این حال، این در واقع چیزی را در سطح کد اعمال نمی کند. توسعه دهندگان فقط می دانند که نباید مستقیماً به ویژگی هایی که با آنها شروع می شود دسترسی داشته باشند _
. با پروکسی ها می توانیم آن را تغییر دهیم.
بیایید خود را به روز کنیم person
شی با شماره تامین اجتماعی در ملکی به نام _ssn
:
const person = {
firstName: 'John',
lastName: 'Doe',
age: 21,
_ssn: '123-45-6789'
};
حالا بیایید آن را ویرایش کنیم get()
تله برای انداختن یک استثنا در صورتی که کسی سعی می کند به خاصیتی دسترسی پیدا کند که با خط زیر شروع می شود:
const handler = {
get(target, property) {
if (property(0) === '_') {
throw new Error(`${property} is a private property`);
}
return target(property);
}
}
const proxyPerson = new Proxy(person, handler);
console.log(proxyPerson._ssn);
اگر این کد را اجرا کنید، باید پیغام خطای زیر را مشاهده کنید روی شما console:
Error: _ssn is a private property
را تنظیم() دام
حالا بیایید نگاهی به آن بیاندازیم set()
trap، که رفتار را هنگام تنظیم مقادیر کنترل می کند روی ویژگی یک شی هدف برای اینکه مثال واضحی به شما بدهیم، فرض می کنیم وقتی a را تعریف می کنید person
اعتراض به ارزش age
باید در محدوده باشد 0
به 150
.
همانطور که قبلاً می دانید، جاوا اسکریپت یک زبان تایپ پویا است، به این معنی که یک متغیر می تواند هر نوع مقدار (رشته، عدد، bool و غیره) را در هر زمان معینی داشته باشد. بنابراین به طور معمول اجرای آن بسیار دشوار است age
دارایی برای نگه داشتن اعداد صحیح با این حال، با پراکسیها، میتوانیم روش تنظیم مقادیر برای ویژگیها را کنترل کنیم:
const handler = {
set(target, property, value) {
if (property === 'age') {
if (!(typeof value === 'number')) {
throw new Error('Age should be a number');
}
if (value < 0 || value > 150) {
throw new Error("Age value should be in between 0 and 150");
}
}
target(property) = value;
}
};
const proxyPerson = new Proxy(person, handler);
proxyPerson.age = 170;
همانطور که در این کد می بینید، the set()
trap سه پارامتر را می پذیرد که عبارتند از:
target
: شی هدفی که پراکسی به آن متصل شده استproperty
: نام ملک در حال تنظیمvalue
: مقداری که به ملک اختصاص داده می شود
در این تله بررسی کرده ایم که آیا نام ملک است یا خیر age
، و اگر چنین است، اگر آن هم یک عدد است و مقدار آن بین 0 تا 150 است – اگر اینطور نباشد خطا می دهد.
وقتی این کد را اجرا می کنید، باید پیغام خطای زیر را مشاهده کنید روی را console:
Error: Age value should be in between 0 and 150
همچنین، میتوانید یک مقدار رشته را تعیین کنید و ببینید آیا خطایی ایجاد میکند یا خیر.
را deleteProperty() دام
حالا بیایید حرکت کنیم روی به deleteProperty()
تله ای که هنگام تلاش برای حذف یک ویژگی از یک شی فعال می شود:
const handler = {
deleteProperty(target, property) {
console.log('You have deleted', property);
delete target(property);
}
};
const proxyPerson = new Proxy(person, handler);
delete proxyPerson.age;
همانطور که می بینید، deleteProperty()
دام نیز می پذیرد target
و property
مولفه های.
اگر این کد را اجرا کنید باید خروجی زیر را ببینید:
You have deleted age
استفاده از پروکسی با توابع
را درخواست دادن() دام
را apply()
trap برای شناسایی زمان فراخوانی تابع استفاده می شود روی شیء پروکسی اول از همه، بیایید یک شخص با نام و نام خانوادگی ایجاد کنیم:
const person = {
firstName: 'Sherlock',
lastName: 'Holmes'
};
سپس یک روش برای دریافت نام کامل:
const getFullName = (person) => {
return person.firstName + ' ' + person.lastName;
};
حال، بیایید یک متد پراکسی ایجاد کنیم که خروجی تابع را با ارائه یک حروف بزرگ به حروف بزرگ تبدیل می کند. apply()
تله داخل کنترل کننده ما:
const getFullNameProxy = new Proxy(getFullName, {
apply(target, thisArg, args) {
return target(...args).toUpperCase();
}
});
console.log(getFullNameProxy(person));
همانطور که در این مثال کد می بینید، the apply()
زمانی که تابع فراخوانی شود trap فراخوانی می شود. سه پارامتر را می پذیرد – target
، thisArg
(که هست this
استدلال برای تماس)، و args
، که لیستی از آرگومان های ارسال شده به تابع است.
ما استفاده کرده ایم apply()
trap برای اجرای تابع هدف با آرگومان های داده شده با استفاده از نحو گسترش ES6 و تبدیل نتیجه به حروف بزرگ. بنابراین شما باید نام کامل را با حروف بزرگ ببینید:
SHERLOCK HOLMES
ویژگی های محاسبه شده با پراکسی ها
خصوصیات محاسبه شده خصوصیاتی هستند که با انجام عملیات محاسبه می شوند روی سایر املاک موجود به عنوان مثال، فرض کنید یک داریم person
شی با ویژگی ها firstName
و lastName
. با این کار، نام کامل می تواند ترکیبی از آن ویژگی ها باشد، درست مانند مثال آخر ما. بنابراین، نام کامل a است دارایی محاسبه شده.
ابتدا بیایید دوباره a ایجاد کنیم person
شیء با نام و نام خانوادگی:
const person = {
firstName: 'John',
lastName: 'Doe'
};
سپس می توانیم یک هندلر با استفاده از get()
تله برای برگرداندن نام کامل محاسبه شده، که با ایجاد یک پروکسی از person
:
const handler = {
get(target, property) {
if (property === 'fullName') {
return target.firstName + ' ' + target.lastName;
}
return target(property);
}
};
const proxyPerson = new Proxy(person, handler);
حالا بیایید سعی کنیم به نام کامل شخص پروکسی دسترسی پیدا کنیم:
console.log(proxyPerson.fullName);
John Doe
فقط با استفاده از پروکسی، یک متد “getter” ایجاد کرده ایم روی را person
بدون نیاز به تغییر واقعی خود شی اصلی.
حال، بیایید نمونه دیگری را ببینیم که پویاتر از آنچه تاکنون با آن مواجه شده ایم. این بار به جای اینکه فقط یک ویژگی را برگردانیم، تابعی را برمی گردانیم که به صورت پویا بر اساس ایجاد شده است روی نام تابع داده شده
آرایه ای از افراد را در نظر بگیرید، جایی که هر شی دارای یک عدد است id
از شخص، نام شخص و سن شخص. ما نیاز به پرس و جو از یک شخص توسط id
، name
، یا age
. بنابراین به سادگی می توانیم چند روش ایجاد کنیم، getById
، getByName
، و getByAge
. اما این بار می خواهیم تا حدودی جلوتر برویم.
ما می خواهیم یک کنترل کننده ایجاد کنیم که بتواند این کار را برای آرایه ای که ممکن است دارای هر خاصیتی باشد، انجام دهد. مثلاً اگر آرایه ای از کتاب ها داشته باشیم و هر کتابی یک خاصیت داشته باشد isbn
، همچنین باید بتوانیم با استفاده از این آرایه پرس و جو کنیم getByIsbn
و روش باید به صورت پویا تولید شود روی زمان اجرا
اما فعلا بیایید مجموعه ای از افراد ایجاد کنیم.
const people = (
{
id: 1,
name: 'John Doe',
age: 21
},
{
id: 2,
name: 'Ann Clair',
age: 24
},
{
id: 3,
name: 'Sherlock Holmes',
age: 35
}
);
حالا بیایید a ایجاد کنیم get
تله برای تولید تابع پویا با توجه به نام تابع.
const proxyPeople = new Proxy(people, {
get(target, property) {
if (property.startsWith('getBy')) {
let prop = property.replace('getBy', '')
.toLowerCase();
return function(value) {
for (let i of target) {
if (i(prop) === value) {
return i;
}
}
}
}
return target(property);
}
});
در این کد ابتدا بررسی میکنیم که آیا نام ویژگی با “getBy” شروع میشود یا نه، سپس “getBy” را از نام ویژگی حذف میکنیم، بنابراین در نهایت به نام خاصیت واقعی میرسیم که میخواهیم از آن برای پرسوجو مورد استفاده کنیم. بنابراین، برای مثال، اگر نام ملک است getById
، ما در نهایت با id
به عنوان ویژگی برای پرس و جو توسط.
اکنون نام خاصیت را داریم که میخواهیم با آن پرس و جو کنیم، بنابراین میتوانیم تابعی را برگردانیم که یک مقدار را میپذیرد و از طریق آرایه تکرار کنیم تا یک شی با آن مقدار پیدا کنیم و روی ملک داده شده
شما می توانید این را با اجرای موارد زیر امتحان کنید:
console.log(proxyPeople.getById(1));
console.log(proxyPeople.getByName('Ann Clair'));
console.log(proxyPeople.getByAge(35));
شی شخص مربوطه برای هر تماس باید نشان داده شود روی را console:
{ id: 1, name: 'John Doe', age: 21 }
{ id: 2, name: 'Ann Clair', age: 24 }
{ id: 3, name: 'Sherlock Holmes', age: 35 }
در خط اول استفاده کردیم proxyPeople.getById(1)
، که سپس کاربر را با علامت باز می گرداند id
از 1. در خط دوم استفاده کردیم proxyPeople.getByName('Ann Clair')
، که شخص را با نام “Ann Clair” برگرداند و غیره روی.
به عنوان تمرینی برای خواننده، سعی کنید آرایه کتاب خود را با ویژگی ها ایجاد کنید isbn
، title
، و author
. سپس با استفاده از کدهای مشابه بالا، ببینید چگونه می توانید استفاده کنید getByIsbn
، getByTitle
، و getByAuthor
برای بازیابی موارد از لیست
برای سادگی، در این پیاده سازی فرض کرده ایم که برای هر ویژگی فقط یک شی با مقدار مشخص وجود دارد. اما ممکن است در برخی موقعیتها اینطور نباشد، که میتوانید آن متد را ویرایش کنید تا آرایهای از اشیاء را که با کوئری داده شده مطابقت دارند، برگردانید.
نتیجه
کد منبع این مقاله موجود است روی GitHub مثل همیشه. اگر در طول آموزش گیر کردید از این برای مقایسه کد خود استفاده کنید.
منتشر شده در 1403-01-23 22:02:06