هل سلاسل جافا سكريبت غير قابلة للتغيير؟هل أحتاج إلى "منشئ سلسلة" في JavaScript؟

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

  •  09-06-2019
  •  | 
  •  

سؤال

هل يستخدم جافا سكريبت سلاسل غير قابلة للتغيير أو قابلة للتغيير؟هل أحتاج إلى "منشئ سلسلة"؟

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

المحلول

إنهم غير قابلين للتغيير.لا يمكنك تغيير حرف داخل سلسلة بشيء مثل var myString = "abbdef"; myString[2] = 'c'.طرق معالجة السلسلة مثل trim, slice إرجاع سلاسل جديدة.

وبنفس الطريقة، إذا كان لديك مرجعين لنفس السلسلة، فإن تعديل أحدهما لا يؤثر على الآخر

let a = b = "hello";
a = a + " world";
// b is not affected

ومع ذلك، لقد سمعت دائمًا ما ذكره Ash في إجابته (أن استخدام Array.join أسرع للتسلسل) لذلك أردت اختبار الطرق المختلفة لتسلسل السلاسل واستخلاص أسرع طريقة في StringBuilder.لقد كتبت بعض الاختبارات لمعرفة ما إذا كان هذا صحيحًا (ليس كذلك!).

كان هذا هو ما اعتقدت أنه سيكون أسرع طريقة، على الرغم من أنني ظللت أفكر في أن إضافة استدعاء الأسلوب قد يجعله أبطأ ...

function StringBuilder() {
    this._array = [];
    this._index = 0;
}

StringBuilder.prototype.append = function (str) {
    this._array[this._index] = str;
    this._index++;
}

StringBuilder.prototype.toString = function () {
    return this._array.join('');
}

فيما يلي اختبارات سرعة الأداء.يقوم الثلاثة جميعًا بإنشاء سلسلة عملاقة مكونة من سلسلة "Hello diggity dog" مائة ألف مرة في سلسلة فارغة.

لقد قمت بإنشاء ثلاثة أنواع من الاختبارات

  • استخدام Array.push و Array.join
  • استخدام فهرسة المصفوفة لتجنب Array.push, ، ثم استخدام Array.join
  • تسلسل سلسلة مستقيمة

ثم قمت بإنشاء نفس الاختبارات الثلاثة عن طريق تلخيصها StringBuilderConcat, StringBuilderArrayPush و StringBuilderArrayIndex http://jsperf.com/string-concat-without-sringbuilder/5 يرجى الذهاب إلى هناك وإجراء الاختبارات حتى نتمكن من الحصول على عينة لطيفة.لاحظ أنني أصلحت خطأً صغيرًا، لذا تم مسح بيانات الاختبارات، وسأقوم بتحديث الجدول بمجرد توفر بيانات أداء كافية.اذهب إلى http://jsperf.com/string-concat-without-sringbuilder/5 لجدول البيانات القديم.

فيما يلي بعض الأرقام (آخر تحديث في Ma5rch 2018)، إذا كنت لا تريد اتباع الرابط.الرقم في كل اختبار هو 1000 عملية / ثانية (أعلى أفضل)

| Browser          | Index | Push | Concat | SBIndex | SBPush | SBConcat |
---------------------------------------------------------------------------
| Chrome 71.0.3578 | 988   | 1006 | 2902   | 963     | 1008   | 2902     |
| Firefox 65       | 1979  | 1902 | 2197   | 1917    | 1873   | 1953     |
| Edge             | 593   | 373  | 952    | 361     | 415    | 444      |
| Exploder 11      | 655   | 532  | 761    | 537     | 567    | 387      |
| Opera 58.0.3135  | 1135  | 1200 | 4357   | 1137    | 1188   | 4294     | 

الموجودات

  • في الوقت الحاضر، تتعامل جميع المتصفحات دائمة الخضرة مع تسلسل السلاسل بشكل جيد. Array.join يساعد فقط IE 11

  • بشكل عام، Opera هو الأسرع، 4 مرات أسرع من Array.join

  • فايرفوكس هو الثاني و Array.join هو أبطأ قليلاً في FF ولكنه أبطأ إلى حد كبير (3x) في Chrome.

  • يأتي Chrome في المركز الثالث ولكن سلسلة concat أسرع بثلاث مرات من Array.join

  • يبدو أن إنشاء StringBuilder لا يؤثر على الأداء كثيرًا.

آمل أن يجد شخص آخر هذا مفيدًا

حالة اختبار مختلفة

نظرًا لأنRoyTinker اعتقد أن اختباري كان معيبًا، فقد قمت بإنشاء حالة جديدة لا تنشئ سلسلة كبيرة عن طريق تسلسل نفس السلسلة، بل تستخدم حرفًا مختلفًا لكل تكرار.لا يزال تسلسل السلاسل يبدو أسرع أو بنفس السرعة.دعونا نجري تلك الاختبارات.

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

http://jsperf.com/string-concat-without-sringbuilder/7

نصائح أخرى

من كتاب وحيد القرن:

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

نصيحة الأداء:

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

لا يوجد StringBuilder في جافا سكريبت.

السلاسل غير قابلة للتغيير - لا يمكنها أن تتغير، ولا يمكننا إلا أن نصنع خيوطًا جديدة.

مثال:

var str= "Immutable value"; // it is immutable

var other= statement.slice(2, 10); // new string

قيمة نوع السلسلة غير قابلة للتغيير، لكن كائن السلسلة، الذي تم إنشاؤه باستخدام مُنشئ String()، قابل للتغيير، لأنه كائن ويمكنك إضافة خصائص جديدة إليه.

> var str = new String("test")
undefined
> str
[String: 'test']
> str.newProp = "some value"
'some value'
> str
{ [String: 'test'] newProp: 'some value' }

وفي الوقت نفسه، على الرغم من أنه يمكنك إضافة خصائص جديدة، إلا أنه لا يمكنك تغيير الخصائص الموجودة بالفعل

لقطة شاشة للاختبار في وحدة تحكم Chrome

في الختام ، 1.كل قيمة نوع السلسلة (النوع البدائي) غير قابلة للتغيير.2.كائن السلسلة قابل للتغيير، لكن قيمة نوع السلسلة (النوع البدائي) التي يحتوي عليها غير قابلة للتغيير.

فقط للتوضيح للعقول البسيطة مثلي (من MDN):

العناصر غير القابلة للتغيير هي الكائنات التي لا يمكن تغيير حالتها بمجرد إنشاء الكائن.

السلسلة والأرقام غير قابلة للتغيير.

غير قابل للتغيير يعني:

يمكنك جعل اسم المتغير يشير إلى قيمة جديدة، لكن القيمة السابقة تظل محفوظة في الذاكرة.ومن هنا الحاجة إلى جمع القمامة.

var immutableString = "Hello";

// في الكود أعلاه، يتم إنشاء كائن جديد بقيمة سلسلة.

immutableString = immutableString + "World";

// نقوم الآن بإلحاق "العالم" بالقيمة الحالية.

يبدو أننا نقوم بتغيير السلسلة "immutableString"، لكننا لسنا كذلك.بدلاً من:

عند إلحاق "immutableString" بقيمة سلسلة، تحدث الأحداث التالية:

  1. يتم استرداد القيمة الموجودة لـ "immutableString".
  2. يتم إلحاق "العالم" بالقيمة الحالية لـ "immutableString"
  3. ثم يتم تخصيص القيمة الناتجة لكتلة جديدة من الذاكرة
  4. يشير الكائن "immutableString" الآن إلى مساحة الذاكرة التي تم إنشاؤها حديثًا
  5. مساحة الذاكرة التي تم إنشاؤها مسبقًا متاحة الآن لجمع البيانات المهملة.

فيما يتعلق بسؤالك (في تعليقك على رد Ash) حول StringBuilder في ASP.NET Ajax، يبدو أن الخبراء يختلفون حول هذا السؤال.

يقول كريستيان وينز في كتابه برمجة ASP.NET أجاكس (O'Reilly) أن "هذا النهج ليس له أي تأثير قابل للقياس على الذاكرة (في الواقع، يبدو أن التنفيذ أبطأ من النهج القياسي)."

ومن ناحية أخرى يقول جالو وآخرون في كتابهم ASP.NET AJAX قيد التنفيذ (مانينغ) أنه "عندما يكون عدد السلاسل المراد ربطها أكبر، يصبح منشئ السلسلة كائنًا أساسيًا لتجنب الانخفاض الكبير في الأداء."

أعتقد أنك ستحتاج إلى إجراء قياس الأداء الخاص بك وقد تختلف النتائج بين المتصفحات أيضًا.ومع ذلك، حتى لو لم يحسن الأداء، فقد يظل يعتبر "مفيدًا" للمبرمجين الذين اعتادوا على البرمجة باستخدام StringBuilders بلغات مثل C# أو Java.

إنها مشاركة متأخرة، لكنني لم أجد اقتباسًا جيدًا لكتاب بين الإجابات.

وهذا قطعي إلا من كتاب موثوق:

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

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

تم توضيح المفهوم الخاطئ "المرجع/القيمة" في "جافا سكريبت الاحترافية"، الفصل المسمى "القيم الأولية والمرجعية":

الأنواع الخمسة البدائية...[هي]:غير محدد، فارغ، منطقي، رقم، وسلسلة.يقال أنه يمكن الوصول إلى هذه المتغيرات من خلال القيمة، لأنك تقوم بمعالجة القيمة الفعلية المخزنة في المتغير. —جافا سكريبت الاحترافية لمطوري الويب، الطبعة الثالثة، ص.85

هذا يتعارض مع أشياء:

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

سلاسل جافا سكريبت غير قابلة للتغيير بالفعل.

السلاسل النصية في Javascript غير قابلة للتغيير

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