يتم اعتبار رقم مفاتيح المصفوفات و"الرقم" متماثلين بشكل غير متوقع

StackOverflow https://stackoverflow.com/questions/453765

سؤال

لقد كنت ألعب بمصفوفات جافا سكريبت وواجهت، ما أشعر به، هو بعض التناقضات، وآمل أن يتمكن شخص ما من شرحها لي.

لنبدأ بهذا:


var myArray = [1, 2, 3, 4, 5];
document.write("Length: " + myArray.length + "<br />");
for( var i in myArray){
   document.write( "myArray[" + i + "] = " + myArray[i] + "<br />");
}
document.write(myArray.join(", ") + "<br /><br />");
Length: 5
myArray[0] = 1
myArray[1] = 2
myArray[2] = 3
myArray[3] = 4
myArray[4] = 5
1, 2, 3, 4, 5

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

قبل المتابعة، اسمحوا لي أن ألاحظ كيفية تحويل قيم السلسلة إلى قيم رقمية في جافا سكريبت.

  • سلسلة غير فارغة -> القيمة الرقمية للسلسلة أو NaN

  • سلسلة فارغة -> 0

وبما أن مصفوفة جافا سكريبت هي كائن، فإن ما يلي قانوني:


myArray["someThing"] = "someThing";
myArray[""] = "Empty String";
myArray["4"] = "four";

لـ (var i in myarray) {document.write ("myarray [" + i + "] =" + myarray [i] + "u003Cbr /> ") ؛} document.write (myarray.join ("،") + "u003Cbr />u003Cbr /> ") ؛

Length: 5
myArray[0] = 1
myArray[1] = 2
myArray[2] = 3
myArray[3] = 4
myArray[4] = four
myArray[someThing] = someThing
myArray[] = Empty String
1, 2, 3, 4, four

الإخراج غير متوقع.

يتم تحويل السلسلة غير الفارغة "4" إلى قيمتها الرقمية عند تعيين الخاصية myArray["4"]، ويبدو هذا صحيحًا.ومع ذلك، لا يتم تحويل السلسلة الفارغة "" إلى قيمتها الرقمية، 0، بل يتم معاملتها كسلسلة فارغة.كما أن السلسلة غير الفارغة "something" لا يتم تحويلها إلى قيمتها الرقمية، NaN، بل يتم التعامل معها كسلسلة.إذن ما هو؟هل العبارة الموجودة داخل myArray[] في سياق رقمي أم سلسلة؟

أيضًا، لماذا لم يتم تضمين الخاصيتين غير الرقميتين لـ myArray في myArray.length و myArray.join("، ")؟

هل كانت مفيدة؟

المحلول

مفاتيح مصفوفة JavaScript هي في الواقع سلاسل.للحصول على تفاصيل وتنفيذ نوع الخريطة للمفاتيح العشوائية، تحقق هذه الإجابة.


للتوضيح والإضافة إلى ما نشره جيسون:صفائف جافا سكريبت هي كائنات.الكائنات لها خصائص.اسم الخاصية هو قيمة سلسلة.لذلك، يتم تحويل مؤشرات المصفوفة إلى سلاسل أيضًا قبل أن يحدث أي شيء آخر.سيتم التعامل مع اسم الخاصية P على أنه فهرس مصفوفة (أي سيتم استدعاء المصفوفة السحرية الخاصة) إذا كانت الحالات التالية (ECMA-262، 15.4):

ToString(ToUint32(P)) يساوي P وToUint32(P) لا يساوي 2^32 − 1

يمكن التحقق بسهولة من أن المؤشرات الرقمية سيتم تحويلها إلى سلاسل (وليس العكس):

var array = [];
array[1] = 'foo';
array['1'] = 'bar';
array['+1'] = 'baz';
document.writeln(array[1]); // outputs bar

أيضًا، من الممارسات السيئة التكرار على إدخالات المصفوفة باستخدام ملف for..in حلقة - قد تحصل على نتائج غير متوقعة إذا عبث شخص ما ببعض النماذج الأولية (وهو ليس سريعًا أيضًا).استخدم المعيار for(var i= 0; i < array.length; ++i) بدلاً من.

نصائح أخرى

(يحرر:ما يلي ليس صحيحا تماما)

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

يحرر:ما ورد أعلاه ليس صحيحًا تمامًا (كما يظهر مثال كريستوفر foo/bar/baz).مؤشرات التخزين الفعلية وفقا ل مواصفات ECMAscript هي، في الواقع، سلاسل، ولكن إذا كانت مؤشرات صفيف صالحة (أعداد صحيحة غير سالبة) فإن كائن الصفيف [[Put]] الطريقة الخاصة تجعل هذه القيم المحددة مرئية لطرق "المصفوفة" الخاصة بالمصفوفة.

هذا جواب ل مشاركة فيلو.معياره معيب لأنه يستخدم أسماء خصائص مختلفة لإصدار الكائن:كان يجب أن يستخدم i كذلك وليس x.

إذا تم ذلك بشكل صحيح، على سبيل المثال مثل هذا:

var start, end, count = 1000000;

var obj = {},
    array = [];

start = new Date;
for(var i = count; i--; )
    array[i] = i;
end = new Date;
document.writeln(Number(end) - Number(start));

start = new Date;
for(var i = count; i--; )
    obj[i] = i;
end = new Date;
document.writeln(Number(end) - Number(start));

سترى أن الأوقات ستكون قريبة جدًا.في FF3.0.5، يكون إصدار المصفوفة أبطأ باستمرار (في Opera، يكون الأمر على العكس من ذلك).

المصفوفات، مثل أي شيء آخر في JavaScript، هي كائنات.لقد تباركت الكائنات مع تدوين النقطة لتخفيف العبء على المطورين.باستخدام المثال الخاص بك

myArray["someThing"] = "someThing";

هو نفس الكتابة

myArray.someThing = "someThing";

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

في حالة "4"، يمكن تحويله إلى عدد صحيح، وبالتالي يتم استخدامه كمؤشر في المصفوفة.

أنا لا أتفق مع كريستوف عندما قال "يتم تحويل مؤشرات المصفوفة إلى سلاسل".

أولاً، أعتقد أن الأمر يعتمد على التنفيذ...أفترض أن المنفذين (الجيدين) سيعملون على تحسين الوصول إلى المصفوفة، وهناك بعض الطرق الذكية للقيام بذلك.

في الواقع، لقد أجريت اختبارًا صغيرًا، وعلى الرغم من أنه جيد مثل معظم المعايير الدقيقة (أي.ليست موثوقة للغاية)، ومن المثير للاهتمام:

result = ""
var x;

var trueArray = []
var startTime = new Date();
for (var i = 0; i < 100000; i++)
{
  x = "i" + i; // To do the same operations
  trueArray[i] = 1;
}
var endTime = new Date();
result += "With array: " + (endTime - startTime) + "\n";

var sArray = []
var startTime = new Date();
for (var i = 0; i < 100000; i++)
{
  x = "" + i;
  sArray[x] = 1;
}
var endTime = new Date();
result += "With s array: " + (endTime - startTime) + "\n";

var objArray = {}
var startTime = new Date();
for (var i = 0; i < 100000; i++)
{
  x = "i" + i;
  objArray[x] = 1;
}
var endTime = new Date();
result += "With object(i): " + (endTime - startTime) + "\n";

var sobjArray = {}
var startTime = new Date();
for (var i = 0; i < 100000; i++)
{
  x = "" + i;
  sobjArray[x] = 1;
}
var endTime = new Date();
result += "With s object: " + (endTime - startTime) + "\n";

var iobjArray = {}
var startTime = new Date();
for (var i = 0; i < 100000; i++)
{
  x = "" + i;
  iobjArray[i] = 1;
}
var endTime = new Date();
result += "With i object: " + (endTime - startTime) + "\n";


// Then display result

في IE6 أحصل على:مع المصفوفة:1453 مع الكائن:3547
في FF 3.0، أحصل على:مع المصفوفة:83 مع الكائن:226
في Safari 3.1، أحصل على:مع المصفوفة:140 مع الكائن:313
في Opera 9.26، لسبب ما، لا أحصل على النتيجة، ولكن إذا قمت بتقليل عدد الحلقات إلى عُشر عدد الحلقات، فسوف أحصل على:مع المصفوفة:47 مع الكائن:516
في الواقع، تركت Opera يعمل بينما أكتب هذا، وحصلت أخيرًا على النتيجة:مع المصفوفة:281 مع الكائن:166063...

لذلك تم تحسين المصفوفات!والذي هو محظوظ...
مظاهرة كريستوف لم تعجبني.سيكون استنتاجي أكثر هو أن السلاسل التي يمكن تفسيرها كأرقام يتم التعامل معها على هذا النحو، والتي تتوافق مع الصيغة المقتبسة ...

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

[تحرير] أضفت بعض الحلقات، بعد فكرة كريستوف.
في FF3، أحصل على:مع المصفوفة:92 مع مجموعة s:93 مع الكائن (ط):243 مع كائن s:194 مع اعتراضي:125 (تختلف الأداء بين جولات التشغيل، ولكنها متسقة تقريبًا).

لست مقتنعًا تمامًا بهذا العدد الصحيح -> السلسلة -> عدد صحيح ذهابًا وإيابًا، ولا حتى أن ECMA تطلب هذا التسلسل.وطريقة قراءتي لها هي:هي الخاصية عبارة عن سلسلة ويمكن تفسيرها على أنها عدد صحيح، ثم يتم التعامل معها على هذا النحو.

بالطبع، الطريقة الوحيدة المؤكدة لمعرفة ذلك هي النظر إلى التنفيذ...

لقد لاحظت باهتمام أن الكائنات البسيطة التي تحصل على خاصية عدد صحيح أو خاصية يمكن تحويلها إلى عدد صحيح قد تم تحسينها بطريقة ما.ربما لأن الكثير من مبرمجي JS استخدموا كائنات عادية كمصفوفات، لذلك اعتبر المنفذون أنه من المثير للاهتمام تحسين هذه الحالة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top