مقدمة
في ES6 ، يعد مُنشئ الوكيل كائنًا عالميًا يمكن الوصول إليه ، حيث يمكنك جمع المعلومات المختلفة حول العمليات المطلوبة بين الكائن وسلوك كائنات التشغيل المختلفة وإرجاع ما تريد القيام به. تم توزيع وظائف السهم ، وتفكيك الصفيف ، ومعلمات REST والميزات الأخرى في ES6 على نطاق واسع بمجرد تنفيذها ، ولكن نادراً ما ينظر إليها المطورين ميزات مثل الوكيل. من ناحية ، فهذا بسبب توافق المتصفح ، ومن ناحية أخرى ، فذلك بسبب مزايا هذه الميزات التي يحتاج المطورون إلى فهمها بعمق سيناريوهات استخدامهم. أنا شخصياً أحب وكيل ES6 حقًا لأنه يتيح لنا التحكم في الوصول الخارجي إلى الكائنات بطريقة موجزة وسهلة الفهم. في ما يلي ، سأقدم أولاً كيفية استخدام الوكيل ، ثم أدرج أمثلة محددة لشرح سيناريوهات الاستخدام للوكالة.
الوكيل ، انظر الاسم والمعنى ، له وظيفة مشابهة جدًا لوضع الوكيل في وضع التصميم ، والذي يتم استخدامه غالبًا في ثلاثة جوانب:
1. مراقبة الوصول الخارجي إلى الكائنات
2. وظيفة أو تعقيد الطبقة
3. تحقق من العملية أو إدارة الموارد المطلوبة قبل العملية
في بيئة المتصفح التي تدعم الوكيل ، يعد الوكيل كائنًا عالميًا يمكن استخدامه مباشرة. Proxy(target, handler) هو مُنشئ ، target هو الكائن الذي تتم محاكمته ، handlder هو كائن يعلن عن عمليات الوكيل المختلفة ، وأخيراً إرجاع كائن وكيل. في كل مرة يصل فيها العالم الخارجي إلى خصائص الكائن target من خلال كائن الوكيل ، يمر عبر كائن handler . من هذه العملية ، يشبه كائن الوكيل إلى حد كبير الوسيطة (الوسيطة). إذن ما هي العمليات التي يمكن أن يعترض الوكيل؟ العمليات الأكثر شيوعًا هي الحصول على (قراءة) ، تعيين (تعديل) خصائص الكائن ، إلخ. يرجى النقر هنا للحصول على قائمة كاملة بالعمليات المعتقة. بالإضافة إلى ذلك ، يوفر كائن الوكيل أيضًا طريقة revoke يمكنها تسجيل الخروج من جميع عمليات الوكيل في أي وقت. قبل أن نقدم الوكيل رسميًا ، نوصي بأن يكون لديك فهم معين للانعكاس ، وهو أيضًا كائن عالمي جديد يضاف إلى ES6.
أساسي
const target = {name: 'billy bob' ، العمر: 15} ؛ const handler = {get (target ، key ، proxy) {const today = new date () ؛ console.log (`الحصول على طلب تم تقديمه مقابل $ {key} على $ {today}`) ؛ return resparle.get (الهدف ، المفتاح ، الوكيل) ؛ }} ؛ const proxy = New Proxy (Target ، Handler) ؛ proxy.name ؛ // => "الحصول على طلب تم تقديمه للاسم في 21 يوليو 2016 15:26:20 بتوقيت جرينتش+0800 (CST)" // => "Billy Bob" في الكود أعلاه ، نحدد أولاً كائنًا target ليكون وكيلًا ، ثم نعلن عن كائن handler يحتوي على جميع عمليات الوكيل. بعد ذلك ، نستخدم Proxy(target, handler) لإنشاء proxy كائن الوكيل. بعد ذلك ، سيتم معالجة جميع الوصول إلى السمة target باستخدام proxy بواسطة handler .
1. الخروج من وحدة التحقق
لنبدأ بالتحقق من النوع البسيط ، والذي يوضح كيفية استخدام الوكيل لضمان دقة أنواع البيانات:
دع NumericDatastore = {count: 0 ، المبلغ: 1234 ، المجموع: 14} ؛ numericDatastore = New Proxy (numericdatastore ، {set (target ، key ، value ، proxy) {if (typeof value! == 'number') {throw error ("properties in numericdatastore can ne be be be be be be ender. }}) ؛ // تم إلقاء خطأ لأن "foo" ليس numericdatastore.count = "foo" ؛ // تم تعيينه بنجاح numericdatastore.count = 333 ؛إذا كنت ترغب في تطوير التحقق مباشرة لجميع خصائص كائن ما ، فقد يجعل بنية الكود منتفخة بسرعة ، وذلك باستخدام الوكيل ، يمكنك فصل المدقق عن المنطق الأساسي والوصول إلى واحد:
الوظيفة CreateValIdator (الهدف ، المدقق) {إرجاع الوكيل الجديد (الهدف ، {_validator: Valitator ، set (الهدف ، المفتاح ، القيمة ، البروكسي) {if (target.hasOwnProperty (مفتاح)) {let validator = this._validator [key] ؛ $ {key} to $ {value}. } ، Age (val) {return typeof age === 'number' && Age> 18 ؛ }} class person {constructor (name ، age) {this.name = name ؛ this.age = العمر ؛ إرجاع createvalidator (هذا ، personvalidators) ؛ }} const bill = شخص جديد ('bill' ، 25) ؛ // سوف تقوم العمليات التالية بالإبلاغ عن فاتورة خطأ = 0 ؛ bill.age = 'bill' ؛ bill.age = 15 ؛ من خلال فصل المدقق والمنطق الرئيسي ، يمكنك تمديد محتوى personValidators بلا حدود دون التسبب في أضرار مباشرة للفئات أو الوظائف ذات الصلة. لكي نكون أكثر تعقيدًا ، يمكننا أيضًا استخدام الوكيل لمحاكاة فحص النوع للتحقق مما إذا كانت الوظيفة تتلقى معلمات ذات نوع وكمية صحيحة:
دع obj = {pickymethodone: function (obj ، str ، num) { / *... * /} ، pickymethodtwo: function (num ، obj) { / *... * /}} ؛ {get: target ، key ، proxy) {var value = key] ؛ دالة ArgChecker (الاسم ، args ، checkers) {for (var idx = 0 ؛ idx <args.length ؛ idx ++) {var arg = args [idx] ؛ var type = chequers [idx] ؛ if (! arg || typeof arg! == type) {console.warn (`أنت تنفذ بشكل غير صحيح توقيع $ {name}. تحقق من param $ {idx + 1}`) ؛ }}} obj.pickymethodone () ؛ //> أنت تنفذ بشكل غير صحيح توقيع بيكميثودون. تحقق من Param 1 //> أنت تقوم بتنفيذ توقيع Pickymethodone بشكل غير صحيح. تحقق من Param 2 //> أنت تقوم بتنفيذ توقيع Pickymethodone بشكل غير صحيح. تحقق من param 3obj.pickymethodtwo ("wopdapodoo" ، {}) ؛ //> أنت تنفذ بشكل غير صحيح توقيع بيكميثودون. تحقق من param 3obj.pickymethodtwo ("wopdapodoo" ، {}) ؛ //> أنت تنفذ بشكل غير صحيح توقيع بيكميثودون. تحقق من param 3obj.pickymethodtwo ("wopdapodoo" ، {}) ؛ //> أنت تنفذ بشكل غير صحيح توقيع PickyMethodTwo. تحقق من param 1 // لا تحذيرات loggedobj.pickymethodone ({} ، "سلسلة صغيرة" ، 123) ؛ obj.pickymethodone (123 ، {}) ؛2. سمات خاصة
في JavaScript أو اللغات الأخرى ، من المعتاد إضافة _ قبل الاسم المتغير للإشارة إلى أن هذه خاصية خاصة (ليست خاصة حقًا) ، لكن لا يمكننا ضمان عدم الوصول إلى أي شخص أو يعدله. في الكود التالي ، نعلن عن apiKey خاص لتسهيل المكالمات داخل كائن api ، لكننا لا نريد أن نكون قادرين على الوصول إلى api._apiKey من الخارج:
var api = {_apikey: '123ABC456DEF' ،/ * طرق mock التي تستخدم هذا. api._apikey) ؛ // get and mutate _apikeys كما هو مطلوب apikey = api._apikey ؛ api._apikey = '987654321' ؛من الواضح أن الاتفاقية غير مقيدة. باستخدام وكيل ES6 ، يمكننا تنفيذ متغيرات خاصة حقيقية. ما يلي يوضح طريقتين خاصتين مختلفتين لطرق القراءة المختلفة.
الطريقة الأولى هي استخدام Set/الحصول على اعتراض طلبات القراءة والكتابة والعودة undefined:
دع api = {_apikey: '123abc456def' ، getUsers: function () {} ، getUser: function (userId) {} ، setUser: function (userId ، config) {}} ؛ > -1) {refler error (`$ {key} ، يرجى الاطلاع على وثائق API لمزيد من المعلومات GREFSE.GET (الهدف ، المفتاح ، القيمة ، الوكيل) ؛الطريقة الثانية هي استخدام التشغيل في العملية:
var api = {_apikey: '123abc456def' ، getUsers: function () {} ، getUser: function (userId) {} ، setUser: function (userId ، config) {}} ؛ const reverated = ['_apikey'] ؛ ؟ الوكيل غامضة _apikey ... ")}}3. سجل الوصول
بالنسبة للسمات أو الواجهات التي تتصل بشكل متكرر أو تشغيلها ببطء أو تناول المزيد من الموارد في بيئة التنفيذ ، سيرغب المطورون في تسجيل استخدامهم أو أدائهم. في هذا الوقت ، يمكنهم استخدام الوكيل ليكون بمثابة البرامج الوسيطة وتنفيذ وظيفة التسجيل بسهولة:
دع api = {_apikey: '123abc456def' ، getUsers: function () { / * ... * /} ، getUser: function (userId) { / * ... * /} ، setuser: function (userId ، config) { / * /} ؛ console.log (`$ {timestamp} - تسجيل $ {method} request بشكل غير متزامن.) ؛ } ؛}}) ؛ api.getusers () ؛4. الإنذار المبكر والاعتراض
لنفترض أنك لا تريد أن يحذف مطورون آخرون سمة noDelete ، وتريد من المطورين الذين يدعون oldMethod أن يفهموا أن هذه الطريقة قد تم التخلي عنها ، أو أخبر المطورين بعدم تعديل سمة doNotChange ، ثم يمكنك استخدام الوكيل لتنفيذها:
دع Datastore = {nodelete: 1235 ، oldmethod: function () {/*.. const nochange = ['donotchange'] ؛ const dembrecated = ['oldmethod'] ؛ datastore = new proxy (datastore ، {set (target ، key ، value ، proxy) {if (nochange.includes (key)) {throw error (`خطأ! $ {key} is Immutable.`) ؛ خطأ (`$ {key} لا يمكن حذفه. دالة (... args) {reflect.apply (target [key] ، target ، args) ؛ حذف datastore.nodelete ؛ datastore.oldmethod () ؛5. مرشح العملية
ستأخذ بعض العمليات الموارد كثيرًا ، مثل نقل الملفات الكبيرة. في هذا الوقت ، إذا تم إرسال الملف بالفعل في أجزاء ، فلا داعي لجعل المقابل (غير القابل) للطلب الجديد. في هذا الوقت ، يمكنك استخدام الوكيل للكشف عن ميزة الطلب وتصفية أي منها لا يحتاج إلى الاستجابة وأيها تحتاج إلى الاستجابة وفقًا للميزات. يوضح الرمز التالي باختصار كيفية تصفية الميزات ، وليس الرمز الكامل. أعتقد أن الجميع سيفهم الأشياء الرائعة:
دع obj = {getGiantFile: function (fileId) {/*... (isenroute || isDownload) {return false ؛6. وكيل المقاطعة
يدعم البروكسي unproxy target في أي وقت ، والتي يتم استخدامها غالبًا لإرفاق الوصول بالكامل إلى البيانات أو الواجهات. في المثال التالي ، استخدمنا طريقة Proxy.revocable لإنشاء كائن وكيل يقوم بإنجاز الوكلاء:
دع ConsitiveData = {username: 'devbryce'} ؛ const {consitivedata ، revokeaccess} = proxy.revocable (consitivedata ، handler) ؛ function handlesuspectedhack () handlesuspectedhack () ؛ // typeerror: empokedConsole.log (consitiveData.Username) ؛ديكور
الديكور المنفذ في ES7 يعادل وضع الديكور في وضع التصميم. إذا قمت ببساطة بتمييز سيناريوهات الاستخدام للوكيل والديكور ، فيمكن تلخيصها على النحو التالي: تتمثل الوظيفة الأساسية للوكالة في التحكم في وصول العالم الخارجي إلى الوكيل ، والوظيفة الأساسية للديكور هي تعزيز وظائف الديكور. طالما أنها تحدث فرقًا كبيرًا في سيناريوهات الاستخدام الأساسية الخاصة بهم ، فإن وظائف مثل سجلات الوصول ، على الرغم من أن هذه المقالة تستخدم تنفيذ الوكيل ، إلا أنه يمكن أيضًا تنفيذها باستخدام ديكور. يمكن للمطورين الاختيار بحرية بناءً على احتياجات المشروع ومواصفات الفريق وتفضيلاتهم الخاصة.
لخص
لا يزال وكيل ES6 عمليًا للغاية. ميزاتها البسيطة على ما يبدو أنها ذات فائدة كبيرة. آمل أن يكون من المفيد للجميع أن يتعلموا ES6.