Ba’zi manbalardagi tavsiflar va Misconceptionlar
Hammaga mashhur bo’lgan javascript.info
TARJIMASI: Objectlarning primitivelardan asosiy farqlaridan biri shundaki, objectlar “by reference” saqlanadi va ko’chiriladi, primitive qiymatlar: string, number, boolean va boshqalar har doim “butun qiymat sifatida” ko’chiriladi. (“as a whole value”).
Freecodecamp bloglaridan birida
TARJIMASI: Primitive qiymatlar to’g’ridan-to’g’ri o’zgaruvchida saqlanadigan ma’lumotlardir. O’zgaruvchiga primitive qiymat berganimizda, bu qiymatning nusxasi yaratiladi va xotirada saqlanadi. O’zgaruvchiga kiritilgan har qanday o’zgarishlar asl qiymatga ta’sir qilmaydi.
MDN Primitive qiymatlar haqida
Qayerda va qaysi holatda saqlanishini yozilmagan, lekin object wrapper haqida ma’lumot beryapti. Object wrapper va boxing/unboxing haqida to’liqroq ma’lumot berman.
Asl primitive qiymatlar
Tepadagi manbalarga ko‘ra primitive qiymatlar - copied as value, yaʼni qaysidir qiymatni boshqa bir o‘zgaruvchiga berganimizda, o‘sha qiymatni nusxasi yaratilib va xotirada saqlanadi yoki o‘zgaruvchiga tenglashtirilarkan. Tasavvur qiling siz dasturlash tilini yaratmoqchisiz, asosiy aniqlab oladigan ishiz, qanday qilib xotirani boshqarish. Xotira juda qimmat turadi. O’zgaruvchilar, referencelar, katta objectlar, xotirani tozalash, faol/faol emas obyektlar va bundan tashqari juda ko’p xotirani boshqarish usullari. Agar primitive qiymatlar “copied as value” bo’lganda, eheee oddiy narsalar bilan xotirani to’ldirib qoyar edik.
Specification primitive qiymatlar haqida
”Tilni amalga oshirishning eng past darajasida (lowest level) to’g’ridan-to’g’ri ifodalangan” iborasi primitive qiymatlar JavaScript engine tomonidan eng fundamental tarzda saqlanishi va boshqarilishini anglatadi. Primitive qiymatlar yangi o’zgaruvchilarga tayinlanganda ko’chirilgandek ko’rinsa-da, ular hali ham pastroq darajadagi JavaScript engine tomonidan reference qilinishi mumkin.
JavaScript primitive qiymatlarni ichki tomondan qanday boshqaradi
Let x be someValue
dan foydalanib qiymat belgilash nusxa ko’chirish o’rniga mos yozuvlarga o’xshash alias yaratadi. Bu shuni anglatadiki, x
va someValue
bir xil asosiy value’ga refer qiladi.
Majburiy nusxa ko’chirish uchun spec’da aniq ko’rsatilgan: Let x be a copy of someValue
.
Primitive qiymatlar o’zgarmas bo’lsa-da, JavaScript har doim yangi nusxalarni yaratish o’rniga ularga samarali reference qilish orqali saqlashni optimallashtirishi mumkin.
”copied as value” degan keng tarqalgan tushunchani shubha ostiga qo’yadi - aslida ular ko’pincha quyi darajadagi referancelar kabi saqlanadi.
let foo = '...long str...' // bir-xil qiymatlet baz = '...long str...' // bir-xil qiymatlet bar = foo // bir-xil qiymat
Agar ba’zi resourcelarda ko’ra: “copied as a whole value” bo’lganda, memory 3x joy olar edi. Aslida ...long str...
uchun memoryda bir marta reference yaratiladi, boshqa variable’lar o’sha referencega point bo’ladi.
// pseudocode: 0x0000003D00098CCD <--> "...long str..."
foo -> 0x0000003D00098CCD baz -> 0x0000003D00098CCD bar -> 0x0000003D00098CCD// hammasida bir-xil reference, xotiradan yutamiz 🔥
Demo
V8 engine-dagi d8 da debugg qilib ko’ramiz
Rasmda 6-ta o’zgaruvchi mavjud. foo
va me
ichidagi content bir-xil, boshqa o’zgaruvchilarga tenglashtiriyapmiz, faqat name
o’zgaruvchida “Person” content turipti. Bu holatda bizada 2 ta reference yaratishilishi kerak.
asdfghjkl....
Person
Kutilganidek: 2 ta address yaratildi, va shu addresslarga o’zgaruvchilar reference qildi.
// pseudocode:foo = 0x011e00098cc5 // bir-xil, 0 reference String<[509]>me = 0x011e00098cc5 // bir-xil, 0 reference String<[509]>bar = 0x011e00098cc5 // bir-xil, 0 reference String<[509]>bazz = 0x011e00098cc5 // bir-xil, 0 reference String<[509]>big = 0x011e00098cc5 // bir-xil, 0 reference String<[509]>name = 0x011e00098f01 // 1 reference String<[6]>// String<[n]> - n so'z uzunligi
Devtools Memory
Isbotlar
v8 pointer compression
Mozilla Centralning Primitive (JS:Value)
Conclusion
Engine code run qilganda, undagi barcha so’zlar xotirada yoziladi. Oddiy misol addEventListener
so’zi xotirada saqlandi, qachon const some = "addEventListener"
o’zgaruvchiga tenglashtirsak, oldin xotirada o’sha so’z bo’lsa, o’sha addressga point bo’ladi, re-create qilishni hojati yoq.
Ba’zi holatlarda Agent boshqacha yo’l tutishi mumkin. Masalan v8 har doim ham valuelarga reference yaratib o’tirmaydi. Aytaylik for(let i = 0; i < 10000; i++)
bu yerda i
qiymati uchun V8 reference yaratmaydi. Buning o’rniga, u oddiy raqamni ishlatishi yoki hatto register darajasida optimizatsiya qilishi mumkin. Agar yaratganida xotirada 0
dan 10000
reference yaratishga to’g’ri kelar edi, optimization uchun bu ishni qilmaydi. SMI (small integer)larda ham reference yaratilmaydi:
for (let i = 0; i < 1000; ++i) { // tez 🚀 (SMI bo'lgani uchun, reference yaratilmaydi)}
for (let i = 0.1; i < 1000.1; ++i) { // sekin 🐌 (SMI bo'lmagani uchun, har bittasi uchun reference yartiladi)}
LEKIN BU HOLATNI SPECIFICATION TALAB QILMAYDI! Enginelar performance-ni oshirish maqsadida optimization qiladi.