أريد أن أكتب مكتبة فئة JavaScript فعالة ولكن لا يمكنني البدء ؛
حاول قراءة مكتبة الآخرين ، ولكن فهمها كما لو كانت مفهومة ؛
أخطط لدراسة وظائف JS المتقدمة بشكل جيد ، ولكن المحتوى في الكتاب الموثوق متناثر للغاية.
حتى لو كنت تتذكر "الاستخدام" ، فأنت لا تفكر في "الطريقة" عندما تريد "استخدام".
ربما يبدو أن لديك ، مثلي ، قوة غير مرئية تقيد خططنا ، مما يجعلنا نعتقد مرارًا وتكرارًا أن قيود المعرفة قد جعلتنا نستمر في المضي قدمًا.
خلال هذه الفترة ، تضاعفت العديد من الواجبات المنزلية ، وتصميم الدورة التدريبية ، والتقارير التجريبية. من النادر الضغط على القليل من الوقت ، ولا تنام أبدًا ، وفرز الكتب التي قرأتها في الماضي لمجرد أن أكون أقرب إلى كتابة مكتبتي الخاصة.
تتم الإشارة إلى هذه المقالة من "JavaScript Language Essence" و "JavaScript الفعالة". تم تصحيح جميع الأمثلة. بعد فهمهم ، أريد أن أجعل بعض المبادئ "العميقة" أبسط قليلاً.
1. النطاق المتغير
النطاق يشبه الأكسجين للمبرمجين. إنه في كل مكان ، ولا تفكر في الأمر. ولكن عندما يتم تلوثه (مثل استخدام الكائنات العالمية) ، ستشعر بالاختناق (مثل استجابة التطبيق البطيئة). قواعد النطاق الأساسية JavaScript بسيطة ومصممة بعناية وقوية للغاية. يتطلب الاستخدام الفعال لـ JavaScript إتقان بعض المفاهيم الأساسية للنطاق المتغير وفهم بعض المواقف القصوى التي يمكن أن تؤدي إلى مشاكل بعيد المنال والمزعج.
1.1 حاول استخدام المتغيرات العالمية بأقل قدر ممكن
JavaScript من السهل إنشاء متغيرات في مساحة الاسم العالمية. يعد إنشاء متغيرات عالمية بلا مجهود لأنه لا يتطلب أي شكل من أشكال الإعلان ويمكن الوصول إليه تلقائيًا بواسطة جميع رمز البرنامج بأكمله.
بالنسبة لنا المبتدئين ، عند مواجهة احتياجات معينة (على سبيل المثال ، عندما يتم تسجيل البيانات المرسلة ، في انتظار استدعاء وقت معين ، أو عند استخدام وظيفة معينة غالبًا) ، فإننا نفكر أخيرًا في الوظائف العالمية. حتى التفكير الموجه لعملية C Language التي تعلمتها في السنة الأولى من الجذور العميقة ، والنظام مليء بالوظائف. يمكن أن يؤدي تحديد المتغيرات العالمية إلى تلويث مساحات الأسماء العامة المشتركة ويمكن أن يؤدي إلى تعارضات تسمية غير متوقعة. المتغيرات العالمية لا تفضي أيضًا إلى النموذج ، لأنها تسبب اقتران غير ضروري بين المكونات المستقلة في البرنامج. من المتحدث بجدية ، أن الكثير من العالم (بما في ذلك أوراق الأنماط ، وتحديد أنماط Div أو A) ودمجها في تطورات الأشخاص المتعددة سيكون خطأً كارثيًا. هذا هو السبب في أن جميع رمز jQuery ملفوف في تعبير مجهول على الفور - المعاداة مع الوظائف المجهولة. عندما يقوم المتصفح بتحميل ملف jQuery ، يبدأ التنفيذ فورًا بعد استدعاء الوظيفة المجهولة ، وتهيئة الوحدات النمطية المختلفة من jQuery لتجنب تدمير وتلوث المتغيرات العالمية والتأثير على الرموز الأخرى.
نسخة الكود كما يلي:
(وظيفة (نافذة ، غير محددة) {
var jquery = ...
// ...
window.jquery = نافذة. $ = jQuery ؛
}) (نافذة) ؛
بالإضافة إلى ذلك ، قد تظن أنه من المفيد "كتابة كيفية تنظيمه أولاً وتنظيمه لاحقًا" ، لكن المبرمجين الممتازين سوف ينتبهون باستمرار إلى بنية البرنامج ، وتصنيف الوظائف ذات الصلة باستمرار ، ومكونات غير ذات صلة ، وهذه السلوكيات هي جزء من صياغة البرمجة.
نظرًا لأن مساحات الأسماء العالمية هي الطريقة الوحيدة للمكونات المستقلة في برامج JavaScript للتفاعل ، فإن استخدام ضوابط التسمية العالمية أمر لا مفر منه. يجب على المكونات أو المكتبات تحديد بعض المتغيرات العالمية. للاستخدام من قبل أجزاء أخرى من البرنامج. خلاف ذلك ، من الأفضل استخدام المتغيرات المحلية.
نسخة الكود كما يلي:
this.foo ؛ // غير محدد
foo = "Global Foo" ؛
this.foo ؛ // "Global Foo"
var foo = "Global Foo" ؛
this.foo = "تم تغيير" ؛
foo ؛ // تغيرت
تتعرض مساحة الاسم العالمية لـ JavaScript للكائنات العالمية التي يمكن الوصول إليها في النطاق العالمي للبرنامج ، والتي تعمل كقيمة أولية لهذه الكلمة الرئيسية. في متصفح الويب ، يرتبط الكائن العالمي بمتغير النافذة العالمي. هذا يعني أن هناك طريقتان لإنشاء متغير عالمي: أعلن ذلك مع VAR ضمن النطاق العالمي ، أو إضافته إلى الكائن العالمي. تتمثل ميزة استخدام إعلانات VAR في أنه يمكنهم التعبير بوضوح عن تأثير المتغيرات العالمية في نطاق البرنامج.
بالنظر إلى أن الإشارات إلى المتغيرات العالمية الملزمة يمكن أن تتسبب في أخطاء وقت التشغيل ، فإن النطاقات الواضحة والموجزة ستجعل من السهل على مستخدمي التعليمات البرمجية فهم تلك المتغيرات العالمية التي يعلنها البرنامج.
نظرًا لأن الكائن العالمي يوفر آلية استجابة ديناميكية للبيئة العالمية ، يمكن استخدامه للاستعلام عن بيئة قيد التشغيل واكتشاف الميزات المتوفرة على هذا النظام الأساسي.
EG.ES5 يقدم كائن JSON عالمي لقراءة وكتابة بيانات تنسيق JSON.
نسخة الكود كما يلي:
إذا (! this.json) {
this.json = {
تحليل: .. ،
سلسلة: ...
}
}
إذا قمت بتقديم تطبيق JSON ، فيمكنك بالطبع استخدام تطبيقك ببساطة وبدون قيد أو شرط. لكن التطبيقات المدمجة التي توفرها البيئة المضيفة أكثر ملاءمة تقريبًا لأنها مكتوبة في المتصفح في C. لأنها تتحقق بدقة واتساق بشكل صارم وفقًا لمعايير معينة وتوفر أداءً أفضل بشكل عام من تطبيقات الطرف الثالث.
تتطلب التشغيل الأساسي لسلاسل محاكاة تصميم بنية البيانات التي لا يمكن استخدام الأساليب التي توفرها اللغة نفسها. JavaScript ينفذ العمليات الأساسية للصفائف بشكل جيد للغاية. إذا كان الأمر يتعلق فقط باحتياجات التعلم العامة ، فإن فكرة أساليب المحاكاة التي توفرها اللغة نفسها جيدة ، ولكن إذا كنت تستثمر حقًا في التطوير ، فلن تحتاج إلى التفكير في اختيار أساليب JavaScript المضمنة في أقرب وقت ممكن.
1.2 تجنب استخدام مع
يوفر البيان مع أي "راحة" يجعل تطبيقك غير موثوق به وغير فعال. نحتاج إلى استدعاء سلسلة من الطرق على كائن واحد بدوره. يمكن أن يتجنب استخدام العبارة مع الكائنات المكررة بسهولة:
نسخة الكود كما يلي:
حالة الوظيفة (معلومات) {
var widget = widget () ؛
مع (القطعة) {
انتكاسة ("الأزرق") ؛
setforeground ("أبيض") ؛
setText ("الحالة:"+info) ؛
يعرض()؛
}
}
من المغري أيضًا استخدام البيان مع "استيراد" (استيراد) متغيرات من كائن الوحدة النمطية.
نسخة الكود كما يلي:
وظيفة F (x ، y) {
مع (الرياضيات) {
إرجاع دقيقة (جولة (x) ، sqrt (y)) ؛ // اقتباس تجريدي
}
}
في الواقع ، يعامل JavaScript جميع المتغيرات كما هو. يبدأ JavaScript من نطاق الأعمق ويبحث عن المتغيرات في الخارج. تعامل اللغة مع كائن كما لو كان يمثل نطاقًا متغيرًا ، لذلك داخل كتلة الكود ، تبدأ عمليات البحث المتغيرة عن طريق البحث عن سمات الاسم المتغير المحدد. إذا لم يتم العثور على الخاصية في هذا الكائن ، فاستمر في البحث في النطاق الخارجي. يفترض الإشارة إلى كل متغير خارجي في الكتلة ضمنيًا أنه لا توجد سمة تحمل نفس الاسم في الكائن (وأي من كائنات النموذج الأولي). إن إنشاء كائن أو تعديله أو النموذج الأولي في مكان آخر من البرنامج لا يتبع بالضرورة مثل هذه الافتراضات. من المؤكد أن محرك JavaScript لا يقرأ التعليمات البرمجية المحلية للحصول على تلك المتغيرات المحلية التي تستخدمها. يمكن تمثيل نطاق JavaScript كهياكل بيانات داخلية فعالة ، وعمليات البحث المتغيرة سريعة جدًا. ومع ذلك ، نظرًا لأن كتلة الكود تحتاج إلى البحث عن سلسلة النموذج الأولي للكائن للعثور على جميع المتغيرات في الكود مع ، فإن سرعة تشغيلها أقل بكثير من سرعة الكود العام.
بدلاً من اللغة ، من السهل ربط الكائن باسم متغير قصير.
نسخة الكود كما يلي:
حالة الوظيفة (معلومات) {
var w = widget () ؛
W.SetBackground ("Blue") ؛
W.SetForeground ("أبيض") ؛
W.Settext ("الحالة:"+معلومات) ؛
W.Show () ؛
}
في حالات أخرى ، تتمثل أفضل طريقة في ربط المتغيرات المحلية بشكل صريح بالخصائص ذات الصلة.
نسخة الكود كما يلي:
وظيفة F (x ، y) {
var min = math.min ،
جولة = Math.round ،
sqrt = math.sqrt ؛
إرجاع min (الجولة (x) ، sqrt (y)) ؛
}
1.3 كفاءة في الإغلاق
هناك مفهوم واحد لفهم الإغلاق:
أ) يتيح لك JavaScript الرجوع إلى المتغيرات المحددة خارج الوظيفة الحالية.
نسخة الكود كما يلي:
وظيفة makeandwich () {
var magingredient = "زبدة الفول السوداني" ؛
وظيفة جعل (ملء) {
إرجاع magingredient + "و" + ملء ؛
}
إرجاع جعل ("جيلي") ؛
}
Makeandwich () ؛ // "زبدة الفول السوداني والهلام"
ب) حتى إذا كانت الوظيفة الخارجية قد تم إرجاعها ، فلا يزال بإمكان الوظيفة الحالية الرجوع إلى المتغير المحدد بواسطة الوظيفة الخارجية.
نسخة الكود كما يلي:
وظيفة makeandwich () {
var magingredient = "زبدة الفول السوداني" ؛
وظيفة جعل (ملء) {
إرجاع magingredient + "و" + ملء ؛
}
العودة
}
var f = sandwichmaker () ؛
و ("جيلي") ؛ // "زبدة الفول السوداني والهلام"
و ("الموز") ؛ // "زبدة الفول السوداني والموز"
F ("Mallows") ؛ // "زبدة الفول السوداني والمولو"
تحتوي قيم وظيفة JavaScriptD على معلومات أكثر من الكود المطلوب تنفيذها عند استدعائها. علاوة على ذلك ، تخزن قيم وظيفة JavaScript أيضًا المتغيرات التي قد تشير إليها في نطاقها المرفق. وتسمى تلك الوظائف التي تتبع المتغيرات داخل النطاق الذي تغطيه الإغلاق.
وظيفة Make هي إغلاق يشير رمزه إلى متغيرين خارجيين: MagingRedient و Elling. كلما تم استدعاء وظيفة Make ، يمكن أن تشير رمزها إلى هذين المتغيرين لأن الإغلاق يخزن هذين المتغيرين.
يمكن أن تشير الوظيفة إلى أي متغير ضمن نطاقه ، بما في ذلك متغيرات المعلمة والوظيفة الخارجية. يمكننا استخدام هذا لكتابة وظائف أكثر عمومًا.
نسخة الكود كما يلي:
وظيفة makeandwich (magingredient) {
وظيفة جعل (ملء) {
إرجاع magingredient + "و" + ملء ؛
}
العودة
}
var f = sandwichmaker ("Ham") ؛
F ("الجبن") ؛ // "لحم الخنزير والجبن"
F ("الخردل") ؛ // "لحم الخنزير والخردل"
تعد عمليات الإغلاق واحدة من أكثر الميزات الأنيقة والتعبيرية في JavaScript وأيضًا جوهر العديد من التعابير.
ج) يمكن للإغلاق تحديث قيمة المتغير الخارجي. في الواقع ، تخزن الإغلاق إشارات إلى المتغيرات الخارجية ، وليس نسخ من قيمها. لذلك ، يمكن تحديث أي إغلاق مع الوصول إلى هذه المتغيرات الخارجية.
نسخة الكود كما يلي:
مربع الوظيفة () {
var val = غير محدد ؛
يعود {
Set: Function (newVal) {val = newVal ؛} ،
الحصول على: function () {return val ؛} ،
النوع: function () {return typeof val ؛}
} ؛
}
var b = box () ؛
B.Type () ؛ // غير محدد
B.Set (98.6) ؛
B.Get () ؛ // 98.6
B.Type () ؛ // الرقم
ينتج هذا المثال كائن يحتوي على ثلاثة عمليات إغلاق. يتم تعيين هذه الإغلاق الثلاثة ، واكتبها والحصول على الخصائص ، وهم جميعا يشاركون الوصول إلى متغيرات VAL ، وتحديث الإغلاق المحدد قيمة VAL. ثم اتصل واكتب لعرض النتائج المحدثة.
1.4 فهم تحسين الإعلان المتغير
يدعم JavaScript نطاق الطريقة هذا (ستكون الإشارات إلى المتغير FOO مرتبطًا بالنطاق الذي يعلن أن الأقرب إلى متغير FOO) ، ولكنه لا يدعم نطاق مستوى الكتلة (النطاق المحدد بواسطة المتغير ليس أقرب بيان أو كتلة رمز مغلقة).
عدم فهم هذه الميزة سيؤدي إلى بعض الأخطاء الدقيقة:
نسخة الكود كما يلي:
وظيفة Iswinner (لاعب ، آخرون) {
var أعلى = 0 ؛
لـ (var i = 0 ، n = others.length ؛ i <n ؛ i ++) {
var player = others [i] ؛
if (player.score> أعلى) {
أعلى = player.score ؛
}
}
Return Player.score> أعلى ؛
}
1.5 حذار من نطاق خرقاء تعبيرات وظيفة التسمية
نسخة الكود كما يلي:
دالة double (x) {return x*2 ؛ }
var f = function (x) {return x*2 ؛ }
يمكن أيضًا استخدام نفس جزء رمز الوظيفة كتعبير ، ولكن له معاني مختلفة تمامًا. الفرق الرسمي بين الوظائف المجهولة وتعبيرات الوظائف المسماة هو أن الأخير مرتبط بمتغير مع نفس اسم الوظيفة كاسم وظيفته ، والذي يعمل كمتغير محلي للوظيفة. يمكن استخدام هذا لكتابة تعبيرات الوظائف العودية.
نسخة الكود كما يلي:
var f = find find (tree ، key) {
// ...
العثور على (tree.left ، مفتاح) ||
Find (tree.right ، key) ؛
}
تجدر الإشارة إلى أن نطاق الاكتشاف المتغير هو فقط في وظيفته الخاصة. على عكس إعلانات الوظيفة ، لا يمكن الرجوع إلى تعبيرات الوظائف المسمى خارجيًا من خلال اسم وظيفتها الداخلية.
نسخة الكود كما يلي:
Find (MyTree ، "Foo") ؛ // Error: Find لم يتم تعريفه ؛
var constructor = function () {return null ؛ }
var f = function () {
عودة مُنشئ () ؛
} ؛
f () ؛ // {} (في بيئات ES3)
يبدو أن البرنامج سيؤدي إلى إنتاج فارغ ، لكنه سيؤدي بالفعل إلى إنتاج كائن جديد.
نظرًا لأن متغير الوظيفة المسماة يرث كائن. تتمثل طريقة تجنب تلويث كائن في نطاق تعبيرات الوظائف في النظام في تجنب إضافة خصائص في الكائن.
عيب آخر في محرك JavaScript الشهير هو الترويج لإعلان تعبيرات الوظيفة المسماة.
نسخة الكود كما يلي:
var f = function g () {return 17 ؛}
ز () ؛ // 17 (في البيئة غير المشابهة)
حتى أن بعض بيئات JavaScript تستخدم وظيفتين F و G ككائنات مختلفة ، مما يؤدي إلى تخصيص الذاكرة غير الضرورية.
1.6 حذار النطاق الخرقاء لوظائف الكتلة المحلية
نسخة الكود كما يلي:
وظيفة f () {return "Global" ؛ }
اختبار الوظيفة (x) {
الدالة f () {return "local" ؛}
var result = [] ؛
إذا (x) {
النتيجة. push (f ()) ؛
}
النتيجة. push (f ()) ؛
نتيجة نتيجة نتيجة ؛
}
اختبار (صحيح) ؛ // ["محلي" ، "محلي"]
اختبار (خطأ) ؛ //["محلي"]
نسخة الكود كما يلي:
وظيفة f () {return "Global" ؛ }
اختبار الوظيفة (x) {
var result = [] ؛
إذا (x) {
الدالة f () {return "local" ؛}
النتيجة. push (f ()) ؛
}
النتيجة. push (f ()) ؛
نتيجة نتيجة نتيجة ؛
}
اختبار (صحيح) ؛ // ["محلي" ، "محلي"]
اختبار (خطأ) ؛ //["محلي"]
JavaScript ليس له نطاق على مستوى الكتلة ، وبالتالي يجب أن يكون نطاق الوظيفة الداخلية F هو وظيفة الاختبار بأكملها. بعض بيئات JavaScript تفعل ، ولكن ليس كل بيئات JavaScript. تقوم تطبيقات JavaScript بالإبلاغ عن وظائف مثل الأخطاء في الوضع الصارم (البرامج في وضع صارم مع إعلانات وظيفة الكتلة المحلية ستقوم بالإبلاغ عن خطأ في بناء الجملة) ، مما يساعد على اكتشاف التعليمات البرمجية غير المحمولة ، مما يعطي المزيد من الدلالات الحكيمة والإمكانية لإعلانات وظيفة الكتلة المحلية للإصدارات المعيارية المستقبلية. في هذه الحالة ، من الممكن التفكير في إعلان متغير محلي داخل وظيفة الاختبار للإشارة إلى الوظيفة العالمية f.