Underscore: خطأ في طرق سلسلة الصفيف في قيم غير صفيف

تم إنشاؤها على ٢٠ مارس ٢٠١٦  ·  6تعليقات  ·  مصدر: jashkenas/underscore

خطأ في طرق سلسلة الصفيف في القيم غير المصفوفة والتي تختلف عن طرق فئة الصفيف الأخرى.

_().pop(); // error
_('').pop(); // error
_().first() // undefined

التعليق الأكثر فائدة

هذا يطرح مشكلة أخرى ، هل يجب أن نضع أمثال المصفوفات في الصفيف؟

_('hello').first() // 'h'
_('hello').pop() // ?

ال 6 كومينتر

هذا يطرح مشكلة أخرى ، هل يجب أن نضع أمثال المصفوفات في الصفيف؟

_('hello').first() // 'h'
_('hello').pop() // ?

يبدو أن هذا لا يزال يمثل مشكلة - لقد واجهناها بعد أن صدمنا نسختنا من 1.8.3 t0 1.9.0

تحرير: يبدو أنه تم إصلاح هذا في 1.9.1 ، إذا كان الأمر كذلك ، فهل يجب أن تظل هذه المشكلة مفتوحة؟

لا يزال هذا السلوك موجودًا في 1.10.2.

تناقض أكثر إقناعًا في خياري ، حيث يتضمن كلاهما تعديل قيمة في المكان:

Object.assign(undefined, {a: 1})  // error
_().extend({a: 1})  // undefined

Array.prototype.push.call(undefined, 1)  // error
_().push(1)  // error

أوافق إلى حد ما على أن هذا غير متسق.

يجدر النظر في أي نوع من المواقف الواقعية التي من المرجح أن تواجهها وما يمكن توقعه من الكائن المغلف في مثل هذه الحالات.

في منتصف السلسلة ، يمكن التنبؤ بالكائن الملتف. على سبيل المثال ، في السلسلة أدناه ، فإن الكائن الملتف الذي تم تمريره إلى push سيكون إما Array أو undefined . لهذا السبب ، أود أن أزعم أن طرق التضمين Array يجب أن تنفذ فحصًا فارغًا. هذا سهل.

_.chain(something).map(f).push(x)  // hoping to push x to an array

إذا كان من المرجح أن يكون الكائن الملتف المتوقع شيئًا آخر غير المصفوفة ، فيمكن القول إنه خطأ مبرمج. لا مانع من طرح استثناء في هذه الحالة.

_.chain(something).map(f).join('').push(x)  // hoping to push x to a string??

في بداية السلسلة ، قد تبدو القصة مختلفة بعض الشيء للوهلة الأولى ، لكنني سأجادل في أنها هي نفسها ويجب أن نتركها عند نقطة الصفر. على الأقل ، يجب أن يكون السبب هو أن المبرمج لديه سبب لتوقع أن يكون something يشبه المصفوفة القابلة للتغيير ، لأنه بخلاف ذلك ، لن يكون هناك سبب لاستدعاء push :

function giveMeAMutableArraylike(something) {
    _.chain(something).push(x)
}

توقع أن something عبارة عن مصفوفة قابلة للتغيير قد لا يتم تلبيتها لعدة أسباب:

  1. انتهى الأمر باستدعاء giveMeAMutableArraylike بـ null أو undefined لأي سبب كان. هذا مشابه للمثال الأول في سلسلة في الوسط ويمكن معالجته بنفس التحقق الفارغ.
  2. يحاول المتصل جعل giveMeAMutableArraylike يفعل شيئًا من الواضح أنه لا يمكنه فعله ، أي كسر العقد. هذا مشابه للمثال الثاني في السلسلة في الوسط. مرة أخرى ، أعتقد أنه من الجيد إلقاء خطأ في هذه الحالة.
  3. something قيمة مجردة بدلاً من مصفوفة تحتوي على عنصر واحد ، على سبيل المثال ، v بدلاً من [v] . هذا موقف شائع في العديد من واجهات برمجة تطبيقات JavaScript. إذا كان العقد giveMeAMutableArraylike يسمح بذلك ، فمن الواضح أنه من الخطأ إلقاء خطأ بغض النظر عما يحدث لـ v .

في الحالة الأخيرة ، لا يمكن لـ Underscore معرفة ما إذا كان giveMeAMutableArraylike يسمح بعناصر مكشوفة واحدة أم لا ، لذا فإن الأمر متروك لمبرمج giveMeAMutableArraylike لتنفيذ عقده الخاص. لا يوجد شيء يمكن لمكتبة مثل Underscore أن تفعله من شأنه أن يفعل الشيء الصحيح لجميع العقود الممكنة:

| السلوك الحالي | التفاف في مجموعة عنصر واحد
- | --- | ---
يسمح العقد بعنصر واحد مكشوف | _المبرمج يحتاج إلى التدخل_ | تسطير يقوم بالشيء الصحيح تلقائيًا
العقد لا يسمح بعنصر واحد مكشوف | الشرطة السفلية تفعل الشيء الصحيح تلقائيًا | _المبرمج يحتاج إلى التدخل_

أيضًا ، كيف تقرر ما إذا كان يجب تغليف القيمة؟ قد ترغب بعض العقود في التفاف أي شيء ليس Array ، بينما قد يرغب البعض الآخر في تمرير arguments والعناصر العادية كما هي. مرة أخرى ، هذا شيء لا تستطيع مكتبة مثل الشرطة السفلية تخمينه نيابة عن المستخدم.

يمكن تصور المواقف الأكثر غرابة أيضًا ، على سبيل المثال عقد يسمح لكائنات تشبه المصفوفة الثابتة مثل السلاسل والتي ستحولها إلى Array أولاً. من المستحيل تغطية جميع الاختلافات الممكنة. وفقًا لمبدأ التغيير الأقل ، لا توجد حجة مقنعة لدعم بعض العقود على حساب العقود التي تم دعمها بالفعل. هناك أيضًا حجة قوية للإبقاء على التنفيذ عند أدنى حد ممكن.

لذلك أعتقد أن الحل الصحيح هو إدخال شيك فارغ وتركه عند هذا الحد. هذا هو التغيير الوحيد لسلوك Underscore الذي يبدو قابلاً للدفاع عنه في جميع المواقف التي يمكن تصورها ويتوافق أيضًا مع سلوك _.extend . لا يزال من الممكن اعتبار التحقق الفارغ بمثابة إصلاح للخلل ، بينما يؤدي القيام بأي شيء أكثر من ذلك إلى تحويله بسرعة إلى تغيير تعسفي.

jashkenas هل يمكنك تسليط الضوء على هذا؟ إذا وافقت ، فسوف أقوم بإعداد طلب سحب يقوم بتنفيذ الشيك الفارغ.

jgonggrijp - هل يمكنك التفصيل في جملة أو جملتين بالسلوك الذي تريد تنفيذه باستخدام الاختيار الفارغ؟

هل هي أن عمليات المصفوفات ستطرح استثناءً صريحًا عند استدعائها بقيمة فارغة؟ أم أنها لن تعمل عند استدعائها بقيمة باطلة؟

jashkenas نعم. السلوك الذي سأقوم بتنفيذه هو no-op ، باتباع نمط وظائف الصفيف Underscore:

https://github.com/jashkenas/underscore/blob/4cf715f593805ba8d7c5685cd06c82b3cd9b55ae/modules/index.js#L495

فيما عدا أن الشيك length لن يكون مطلوبًا ، لذلك سأدرجه فقط

if (obj == null) return chainresult(this, obj);

بين هذين السطرين:

https://github.com/jashkenas/underscore/blob/4cf715f593805ba8d7c5685cd06c82b3cd9b55ae/modules/index.js#L1654 -L1655

بالإضافة إلى الاختبارات بالطبع ، وإذا كشفت هذه الاختبارات عن وجود حاجة ، فربما يكون أيضًا فحصًا فارغًا يحول الطريقة إلى no-op قبل هذا السطر:

https://github.com/jashkenas/underscore/blob/4cf715f593805ba8d7c5685cd06c82b3cd9b55ae/modules/index.js#L1665

يبدو جيدا بالنسبة لي!

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

sky0014 picture sky0014  ·  8تعليقات

markvr picture markvr  ·  3تعليقات

clouddueling picture clouddueling  ·  3تعليقات

xiaoliwang picture xiaoliwang  ·  3تعليقات

githublyp picture githublyp  ·  3تعليقات