क्या जावास्क्रिप्ट तार अपरिवर्तनीय हैं? क्या मुझे जावास्क्रिप्ट में "स्ट्रिंग बिल्डर" की आवश्यकता है?


237

क्या जावास्क्रिप्ट अपरिवर्तनीय या परिवर्तनशील तार का उपयोग करता है? क्या मुझे "स्ट्रिंग बिल्डर" की आवश्यकता है?


3
हां, y अपरिवर्तनीय हैं और आपको किसी प्रकार के "स्ट्रिंग बिल्डर" की आवश्यकता है। इस ब्लॉग को पढ़ें ।codeeffects.com / Article / String
Builder

2
दिलचस्प है, वे उदाहरण मेरे जवाब में मेरे निष्कर्षों का खंडन करते हैं।
जुआन मेंडेस

जवाबों:


294

वे अपरिवर्तनीय हैं। आप कुछ के साथ एक स्ट्रिंग के भीतर एक चरित्र को बदल नहीं सकते var myString = "abbdef"; myString[2] = 'c'। स्ट्रिंग हेरफेर करने के तरीके जैसे trim, sliceनए तार लौटाते हैं।

उसी तरह, यदि आपके पास एक ही स्ट्रिंग के दो संदर्भ हैं, तो एक को संशोधित करना दूसरे को प्रभावित नहीं करता है

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

हालाँकि, मैंने हमेशा यह सुना है कि ऐश ने अपने उत्तर में क्या उल्लेख किया है (कि एरे.जॉइन का उपयोग करना संघनन के लिए तेज है) इसलिए मैं स्ट्रिंग्स को अलग करने और स्ट्रैंगबुइटल में सबसे तेज़ तरीके से अमूर्त करने के विभिन्न तरीकों का परीक्षण करना चाहता था। मैंने यह देखने के लिए कुछ परीक्षण लिखे कि क्या यह सच है (यह नहीं है!)।

मेरा मानना ​​था कि यह सबसे तेज़ तरीका होगा, हालांकि मैं यह सोचता रहा कि मेथड कॉल जोड़ने से यह धीमा हो सकता है ...

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 में मदद करता है

  • कुल मिलाकर, ओपेरा सबसे तेज है, अर्रे.जॉइन की तुलना में 4 गुना तेज है

  • फ़ायरफ़ॉक्स दूसरा है और Array.joinकेवल FF में थोड़ा धीमा है लेकिन क्रोम में काफी धीमा (3x) है।

  • Chrome तीसरा है लेकिन Array.join की तुलना में स्ट्रिंग कॉनैट 3 गुना तेज है

  • ऐसा लगता है कि StringBuilder बनाना पूर्णता को बहुत अधिक प्रभावित नहीं करता है।

आशा है कि किसी और को यह उपयोगी लगता है

अलग-अलग टेस्ट केस

चूंकि @RoyTinker ने सोचा था कि मेरा परीक्षण त्रुटिपूर्ण था, मैंने एक नया मामला बनाया जो एक ही स्ट्रिंग को समेट कर एक बड़ा स्ट्रिंग नहीं बनाता है, यह प्रत्येक पुनरावृत्ति के लिए एक अलग वर्ण का उपयोग करता है। स्ट्रिंग संघनन अभी भी तेज या सिर्फ तेज लग रहा था। चलिए वो टेस्ट चल रहे हैं।

मेरा सुझाव है कि हर किसी को इसे परखने के अन्य तरीकों के बारे में सोचना चाहिए, और नीचे दिए गए अलग-अलग परीक्षण मामलों में नए लिंक जोड़ने के लिए स्वतंत्र महसूस करना चाहिए।

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


@ जुआन, जिस लिंक पर आपने हमें यात्रा करने के लिए कहा है, वह ३०१-चार स्ट्रिंग स्ट्रिंग ३० बार है। यहां एक और परीक्षण है जो चीजों को संतुलित करने में मदद कर सकता है - Array.join vs string concatenation 20,000 विभिन्न 1-char स्ट्रिंग्स ( Join IE / FF पर बहुत तेज़ है)। jsperf.com/join-vs-str-concat-large-array
रॉय टिंकर

1
@RoyTinker रॉय, ओह रॉय, आपके परीक्षण धोखा दे रहे हैं क्योंकि आप परीक्षण के सेटअप में सरणी बना रहे हैं। यहाँ विभिन्न पात्रों का उपयोग कर असली परीक्षा है jsperf.com/string-concat-without-sringbuilder/7 नए टेस्ट केस बनाने के लिए स्वतंत्र महसूस करें, लेकिन एरे का निर्माण खुद टेस्ट का हिस्सा है
जुआन मेंडेस

@JuanMendes मेरा लक्ष्य परीक्षण मामले को joinबनाम स्ट्रिंग संघनन की एक सख्त तुलना में संकीर्ण करना था , इसलिए परीक्षण से पहले सरणी का निर्माण करना। मुझे नहीं लगता कि यह धोखा है अगर उस लक्ष्य को समझा जाता है (और joinसरणी को आंतरिक रूप से माना जाता है , इसलिए यह परीक्षण forसे लूप को धोखा देने के लिए धोखा नहीं है join, या तो)।
रॉय टिंकर

2
@RoyTinker हाँ यह है, किसी भी स्ट्रिंग बिल्डर को सरणी के निर्माण की आवश्यकता होगी। सवाल यह है कि क्या एक स्ट्रिंग बिल्डर की जरूरत है। यदि आपके पास पहले से ही एक सरणी में तार हैं, तो हम यहां जो चर्चा कर रहे हैं, उसके लिए यह वैध परीक्षण मामला नहीं है
जुआन मेंडेस

1
@Baltusaj इंडेक्स / पुश का उपयोग करने वाले कॉलमArray.join
जुआन मेंडेस

41

से राइनो किताब :

जावास्क्रिप्ट में, स्ट्रिंग्स अपरिवर्तनीय वस्तुएं हैं, जिसका अर्थ है कि उनके भीतर के वर्णों को नहीं बदला जा सकता है और यह कि स्ट्रिंग्स पर कोई भी ऑपरेशन वास्तव में नए स्ट्रिंग्स बनाते हैं। स्ट्रिंग्स को संदर्भ द्वारा निर्दिष्ट किया जाता है, मूल्य द्वारा नहीं। सामान्य तौर पर, जब किसी ऑब्जेक्ट को संदर्भ द्वारा असाइन किया जाता है, तो ऑब्जेक्ट के लिए अन्य सभी संदर्भों के माध्यम से ऑब्जेक्ट में किए गए एक परिवर्तन दिखाई देगा। क्योंकि स्ट्रिंग को बदला नहीं जा सकता है, हालाँकि, आपके पास एक स्ट्रिंग ऑब्जेक्ट के कई संदर्भ हो सकते हैं और चिंता न करें कि स्ट्रिंग मूल्य आपके जानने के बिना बदल जाएगा


7
राइनो पुस्तक के एक उपयुक्त अनुभाग से लिंक करें: books.google.com/…
बॉडटैक

116
राइनो पुस्तक का उद्धरण (और इस प्रकार यह उत्तर) गलत है। जावास्क्रिप्ट में तार आदिम मूल्य प्रकार हैं और न कि ऑब्जेक्ट (युक्ति) । वास्तव में, ईएस 5 के रूप में, वे केवल 5 मान प्रकारों में null undefined numberसे एक हैं boolean। स्ट्रिंग्स को मूल्य द्वारा निर्दिष्ट किया जाता है और संदर्भ द्वारा नहीं और इस तरह से पारित किया जाता है। इस प्रकार, तार सिर्फ अपरिवर्तनीय नहीं हैं, वे एक मूल्य हैं । स्ट्रिंग "hello"को बदलना यह "world"तय करने जैसा है कि अब से नंबर 3 पर नंबर 4 है ... इसका कोई मतलब नहीं है।
बेंजामिन ग्रुएनबाम

8
हाँ, मेरी टिप्पणी की तरह कहते हैं तार कर रहे हैं अपरिवर्तनीय है, लेकिन वे संदर्भ प्रकार नहीं कर रहे हैं और न ही वे वस्तुओं रहे हैं - वे आदिम मूल्य प्रकार हैं। यह देखने का एक आसान तरीका है कि वे न तो एक संपत्ति को एक स्ट्रिंग में जोड़ने की कोशिश करेंगे और फिर इसे पढ़ेंगे:var a = "hello";var b=a;a.x=5;console.log(a.x,b.x);
बेंजामिन ग्रुएनबाउम

9
@ VidarS.Ramdal नहीं, Stringस्ट्रिंग कंस्ट्रक्टर का उपयोग करके बनाई गई ऑब्जेक्ट जावास्क्रिप्ट स्ट्रिंग मानों के आसपास रैपर हैं। आप .valueOf()फ़ंक्शन का उपयोग करके बॉक्सिंग प्रकार के स्ट्रिंग मूल्य तक पहुंच सकते हैं - यह Numberवस्तुओं और संख्या मूल्यों के लिए भी सही है। यह नोट करना महत्वपूर्ण है कि Stringउपयोग की गई वस्तुएं new Stringवास्तविक तार नहीं हैं बल्कि आवरण या हैं तार के आसपास बॉक्स हैं। Es5.github.io/#x15.5.2.1 देखें । वस्तुओं के रूप में चीजों को परिवर्तित करने के बारे में es5.github.io/#x9.9
बेंजामिन

5
जैसा कि कुछ लोग कहते हैं कि तार वस्तुएं हैं, वे शायद पायथन या लिस्प या किसी अन्य भाषा से आ रहे हैं, जहां इसकी कल्पना किसी भी तरह के डेटा (यहां तक ​​कि पूर्णांकों) का अर्थ करने के लिए "ऑब्जेक्ट" शब्द का उपयोग करती है। उन्हें केवल पढ़ने की ज़रूरत है कि ECMA कल्पना कैसे शब्द को परिभाषित करती है: "ऑब्जेक्ट का सदस्य"। इसके अलावा, यहां तक ​​कि "मूल्य" शब्द का मतलब अलग-अलग भाषाओं के चश्मे के अनुसार अलग-अलग चीजें हो सकती हैं।
जिसांग यूओ

21

प्रदर्शन टिप:

यदि आपको बड़े तारों को समतल करना है, तो स्ट्रिंग भागों को एक सरणी में रखें और Array.Join()समग्र स्ट्रिंग प्राप्त करने के लिए विधि का उपयोग करें । बड़ी संख्या में तारों को समतल करने के लिए यह कई गुना तेज हो सकता है।

StringBuilderजावास्क्रिप्ट में कोई भी नहीं है।


मुझे पता है कि कोई स्ट्रांगबर्ल नहीं है, msAjax के पास एक है, और मैं सिर्फ यह सोच रहा था कि इसका उपयोग उपयोगी है या नहीं
विकासशील 3

5
तार के अपरिवर्तनीय होने या न होने से इसका क्या लेना-देना है?
बॉडटैक

4
@docgnome: क्योंकि तार अपरिवर्तनीय हैं, स्ट्रिंग संघनन को Array.join दृष्टिकोण की तुलना में अधिक ऑब्जेक्ट बनाने की आवश्यकता होती है
जुआन मेंडेस

8
ऊपर के जुआन के परीक्षण के अनुसार, फ़ायरफ़ॉक्स में धीमी गति से, स्ट्रिंग कॉनटेनेंस वास्तव में IE और क्रोम दोनों में तेज है।
बिल यांग

9
अपने उत्तर को अपडेट करने पर विचार करें, यह बहुत पहले सच हो सकता है, लेकिन यह अब नहीं है। देखें jsperf.com/string-concat-without-sringbuilder/5
जुआन मेंडेस

8

बस सरल मन के लिए स्पष्ट करने के लिए मेरा ( एमडीएन से ):

अपरिवर्तनीय वस्तुएं हैं जिनका ऑब्जेक्ट बनने के बाद स्थिति को बदला नहीं जा सकता है।

स्ट्रिंग और नंबर अपरिवर्तनीय हैं।

अपरिवर्तनीय का अर्थ है:

आप एक नया नाम पर एक चर नाम बिंदु बना सकते हैं, लेकिन पिछला मान अभी भी स्मृति में है। इसलिए कचरा संग्रहण की आवश्यकता है।

var immutableString = "Hello";

// उपरोक्त कोड में, स्ट्रिंग मान के साथ एक नई वस्तु बनाई गई है।

immutableString = immutableString + "World";

// अब हम मौजूदा मूल्य के लिए "विश्व" जोड़ रहे हैं।

ऐसा लगता है कि हम स्ट्रिंग को 'अपरिवर्तनीय स्ट्रिंग' के रूप में बदल रहे हैं, लेकिन हम नहीं हैं। बजाय:

एक स्ट्रिंग मान के साथ "इम्यूटेबल स्ट्रिंग" को जोड़ने पर, निम्नलिखित घटनाएं होती हैं:

  1. "ImmutableString" का मौजूदा मूल्य पुनर्प्राप्त किया जाता है
  2. "वर्ल्ड" को "इम्यूटेबल स्ट्रींग" के मौजूदा मूल्य से जोड़ा गया है
  3. परिणामी मान को फिर मेमोरी के एक नए ब्लॉक में आवंटित किया जाता है
  4. "immutableString" ऑब्जेक्ट अब नए बनाए गए मेमोरी स्पेस की ओर इशारा करता है
  5. पहले निर्मित मेमोरी स्पेस अब कचरा संग्रहण के लिए उपलब्ध है।

4

स्ट्रिंग प्रकार का मान अपरिवर्तनीय है, लेकिन स्ट्रिंग ऑब्जेक्ट, जो स्ट्रिंग () कंस्ट्रक्टर का उपयोग करके बनाया गया है, वह परिवर्तनशील है, क्योंकि यह एक ऑब्जेक्ट है और आप इसमें नए गुण जोड़ सकते हैं।

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

इस बीच, यद्यपि आप नए गुण जोड़ सकते हैं, आप पहले से मौजूद गुणों को नहीं बदल सकते

क्रोम कंसोल में एक परीक्षण का स्क्रीनशॉट

निष्कर्ष में, 1. सभी स्ट्रिंग प्रकार मान (आदिम प्रकार) अपरिवर्तनीय है। 2. स्ट्रिंग ऑब्जेक्ट उत्परिवर्तनीय है, लेकिन इसमें शामिल स्ट्रिंग प्रकार मान (आदिम प्रकार) अपरिवर्तनीय है।


जावास्क्रिप्ट स्ट्रिंग ऑब्जेक्ट अपरिवर्तनीय डेवलपर हैं
।.mozilla.org

@prasun लेकिन उस पृष्ठ में यह कहा गया है: "वस्तुओं को छोड़कर सभी प्रकार अपरिवर्तनीय मूल्यों (मूल्यों, जो बदले जाने में असमर्थ हैं) को परिभाषित करते हैं।" स्ट्रिंग ऑब्जेक्ट ऑब्जेक्ट हैं। और यह कैसे अपरिवर्तनीय है यदि आप इस पर नए गुण जोड़ सकते हैं?
झांझियांग

"स्ट्रिंग प्रकार" अनुभाग पढ़ें। जावास्क्रिप्ट का स्ट्रिंग लिंक आदिम और वस्तु दोनों को इंगित करता है और बाद में यह कहता है कि "जावास्क्रिप्ट तार अपरिवर्तनीय हैं"। ऐसा लगता है कि दस्तावेज़ इस विषय पर स्पष्ट नहीं है क्योंकि यह दो अलग-अलग नोटों में टकराव करता है
prasun

6
new Stringएक अपरिवर्तनीय स्ट्रिंग के आसपास एक उत्परिवर्तनीय आवरण उत्पन्न करता है
टोमेम्यूइट

1
ऊपर @ zhanziyang का कोड चलाकर परीक्षण करना बहुत आसान है। आप एक Stringऑब्जेक्ट (आवरण) में पूरी तरह से नए गुण जोड़ सकते हैं , जिसका अर्थ है कि यह अपरिवर्तनीय नहीं है (डिफ़ॉल्ट रूप से, किसी अन्य ऑब्जेक्ट की तरह आप Object.freezeइसे अपरिवर्तनीय प्रदान करने के लिए कॉल कर सकते हैं )। लेकिन एक आदिम स्ट्रिंग मान प्रकार, चाहे वह Stringऑब्जेक्ट रैपर में निहित हो या नहीं, हमेशा अपरिवर्तनीय होता है।
मार्क रीड

3

स्ट्रिंग्स अपरिवर्तनीय हैं - वे बदल नहीं सकते हैं, हम केवल कभी भी नए स्ट्रिंग्स बना सकते हैं।

उदाहरण:

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

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

1

ASP.NET Ajax में StringBuilder के बारे में आपके सवाल (ऐश की प्रतिक्रिया के बारे में आपकी टिप्पणी) के बारे में विशेषज्ञ इस पर असहमत लगते हैं।

क्रिश्चियन वेनज़ ने अपनी पुस्तक प्रोग्रामिंग एएसपी.एक्स.एक्सएक्स (ओ'रेली) में कहा है कि "इस दृष्टिकोण का मेमोरी पर कोई औसत दर्जे का प्रभाव नहीं होता है (वास्तव में, कार्यान्वयन मानक दृष्टिकोण की तुलना में एक टिक धीमा लगता है)।"

दूसरी ओर गैलो एट अल अपनी पुस्तक ASP.NET AJAX इन एक्शन (मैनिंग) में कहते हैं कि "जब समतल करने के लिए तारों की संख्या बड़ी होती है, तो स्ट्रिंग बिल्डर विशाल प्रदर्शन ड्रॉप से ​​बचने के लिए एक आवश्यक वस्तु बन जाता है।"

मुझे लगता है कि आपको अपने स्वयं के बेंचमार्किंग करने की आवश्यकता होगी और परिणाम ब्राउज़रों के बीच भी भिन्न हो सकते हैं। हालाँकि, भले ही यह प्रदर्शन में सुधार नहीं करता है, फिर भी इसे प्रोग्रामर के लिए "उपयोगी" माना जा सकता है, जिन्हें C # या Java जैसी भाषाओं में StringBuilders के साथ कोडिंग करने के लिए उपयोग किया जाता है।


1

यह एक देर से पोस्ट है, लेकिन मुझे जवाबों के बीच एक अच्छी पुस्तक उद्धरण नहीं मिला।

यहाँ एक विश्वसनीय पुस्तक को छोड़कर एक निश्चित है:

ECMAScript में स्ट्रिंग्स अपरिवर्तनीय हैं, जिसका अर्थ है कि एक बार बनने के बाद, उनके मान बदल नहीं सकते हैं। एक चर द्वारा आयोजित स्ट्रिंग को बदलने के लिए, मूल स्ट्रिंग को नष्ट कर दिया जाना चाहिए और एक नया मूल्य युक्त एक अन्य स्ट्रिंग से भरा हुआ चर ... - वेब डेवलपर्स के लिए व्यावसायिक जावास्क्रिप्ट, तीसरा संस्करण।, p.43

अब, जो उत्तर राइनो पुस्तक के उद्धरण उद्धृत करता है, वह स्ट्रिंग अपरिवर्तनीयता के बारे में सही है, लेकिन गलत है "स्ट्रिंग्स को संदर्भ द्वारा निर्दिष्ट किया जाता है, मूल्य द्वारा नहीं।" (शायद वे मूल रूप से शब्दों को विपरीत तरीके से रखना चाहते थे)।

"प्रोफेशनल जावास्क्रिप्ट", "आदिम और संदर्भ मूल्य" नामक अध्याय में "संदर्भ / मूल्य" गलत धारणा को स्पष्ट किया गया है:

पाँच आदिम प्रकार ... [हैं]: अपरिभाषित, अशक्त, बूलियन, संख्या और स्ट्रिंग। इन चरों को मान से अभिगम करने के लिए कहा जाता है, क्योंकि आप चर में संग्रहीत वास्तविक मान में हेरफेर कर रहे हैं। वेब डेवलपर्स के लिए पेशेवर जावास्क्रिप्ट, तीसरा संस्करण।, p.85

यह वस्तुओं के विपरीत है :

जब आप किसी ऑब्जेक्ट में हेरफेर करते हैं, तो आप वास्तव में वास्तविक ऑब्जेक्ट के बजाय उस ऑब्जेक्ट के संदर्भ में काम कर रहे होते हैं। इस कारण से, इस तरह के मूल्यों को संदर्भ द्वारा एक्सेस करने के लिए कहा जाता है। वेब डेवलपर्स के लिए पेशेवर जावास्क्रिप्ट, तीसरा संस्करण।, p.85


एफडब्ल्यूआईडब्ल्यू: राइनो पुस्तक का अर्थ है कि आंतरिक रूप से / कार्यान्वयन एक स्ट्रिंग असाइनमेंट एक पॉइंटर को संचयित / कॉपी कर रहा है (बजाय स्ट्रिंग की सामग्री को कॉपी करने के)। यह उनके हिस्से पर एक दुर्घटना की तरह नहीं दिखता है, उसके बाद के पाठ के आधार पर। लेकिन मैं सहमत हूं: वे "संदर्भ द्वारा" शब्द का दुरुपयोग करते हैं। इसका संदर्भ केवल "संदर्भ से" नहीं है क्योंकि कार्यान्वयन संकेत (प्रदर्शन के लिए) से गुजरता है। विकी - मूल्यांकन रणनीति इस विषय पर एक दिलचस्प पढ़ा है।
टूलमेकरसेव

-1

जावास्क्रिप्ट स्ट्रिंग्स वास्तव में अपरिवर्तनीय हैं।


डॉक्टर लिंक? मुझे इस पर कोई विवरण नहीं मिल रहा है।
विकासशील

1
"व्यक्तिगत चरित्र सेट करने का प्रयास करने से काम नहीं चलेगा" - developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
Ken

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.