DEV Community

Cover image for JavaScript Evolutsiyasi Qisqa Satrlarda!
Humoyun Ahmad
Humoyun Ahmad

Posted on • Edited on

JavaScript Evolutsiyasi Qisqa Satrlarda!

Bismillah!

Taxminiy o'qish vaqti: ~9 daqiqa

Diskleymer: ba'zi atamalardan shundayligicha foydalanildi, tarjimasi ga'latiroq yoki notanish ko'rinmasligi uchun. Ba'zi iboralar esa ixchamroq ko'rinishga keltrildi, release -> reliz.

Assalam alaykum! Bugun siz bilan JavaScript (JS) rivojlanish tarixiga biroz nazar tashlaymiz. Hozirgi kunda eng zamonaviy va eng ko'p qo'llaniladigan tillardan hisoblangan JS oldin qanday edi va o'tgan yillar ichida qanchalik o'zgardi va kimlar o'zgartirdi. Bu maqolada JSni boshlanish tarixiga to'xtalib o'tirilmadi, agar bu haqida to'liq bilishni xohlasangiz quyidagi maqoladan o'qib olsangiz bo'ladi: version history of javascript

Ko'p yillar davomida (< 2015 gacha) JS rivojlanishi (tilga yangi imkoniyatlarni qo'shib borish) juda sekin va salmoqsiz edi. Aniqroq gapiradigan bo'lsak, ECMAScript (JS ni spesifikatsiyasiga ma'sul standard) tilni 3.1 versiyasida 2009 dan beri qotib qolgan edi πŸ”’. Solishtirish uchun ushbu havolaga qaralsin. Keyinchalik bu versiya biz ko'proq tanish bo'lgan ECMAScript 5 yoki ES5 nomi bilan almashtirildi. Keyingi katta relizgacha JS community ancha uzoq kutib qoldi, deyarli 6 yil. Xatto ATM mashinalar ham tezroq yangilanib turiladi.

Bu vaqt mobaynida esa TC39 deb nomlangan JSni stardartlashtirish guruhi bir qancha OpenJS Foundation kabi ochiq jamiyatlar yordamida ECMAScript 2015 yoki ES6 versiyasini ishlab chiqishdi va 2015 yilga kelibgina taqdim etishdi. Bu JS tarixidagi shu paytgacha kirtilgan eng katta va muhim yangilanish edi.

Bu relizda JSga kiritilgan yangi imkoniyatlarning eng asosiylari bilan quyida tanishib chiqamiz. To'liq ma'lumotni esa ushbu havoladan ko'rib olsangiz bo'ladi.

Yangi Promise API

Promise obyekti muayyan asinxron operatsiya (serverga http so'rov) bilan ancha qulay tarzda ishlash imkonini beradi. Bu mexanizmdan oldin JSda asinxron kodlar callback lar yordamida amalga oshirilardi lekin noqulayliklari ko'p edi. Bunga yaqqol misol qilib callback hell 😩 keltirish mumkin. Buni quyidagi code-snippet da ko'rishingiz mumkin:

Callback hell sample

Demak Promiselar bizga quyidagilarni beradi:

  1. Yanada ekspressiv asinxron kod yozish.
  2. Yanada elegant error handling.

ekspressiv - qisqa satrlarda ko'p narsani namoyon eta olish.
elegant - nafis va yoqimli ko'rinish.

Qo'shimcha: ES7 async/await sintaksisi esa asinxron kodingni yanada qulaylashtirdi.

Class sintaksisi

Classlar JSning prototype mexanizmi ustiga qurilgan abstraksiyasidir. Javadagi classlar bilan adashtirilmasin chunki sintaktik bir xil ko'rinishda bo'lsada, ishlash mexamizmlari fundamental darajada bir biridan farqlidir. JSda haqiqiy Prototypal Inheritance (aslida Delegation) ni to'g'ri setup qilish biroz murakkabroq jarayon edi, classlar buni elegant holatga keltirdi.

// classlarsiz
function Person() {...}
Person.prototype.getName = function () {...}

function Student() {}
Student.prototype.getScores = function () {...}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

// classlar bilan
class Person {
  getName() {...}
}
class Student extends Person {
  getScores() {...}
}
Enter fullscreen mode Exit fullscreen mode

Lekin bu degani classlar yaxshiroq degani emas. Uni o'ziga yarasha kamchililari bor. Bu haqida esa boshqa maqolada bafurja muhokama qilamiz. Shaxsan men uchun classlar JSda obyektlar bilan ishlashga turli tumanlikni olib kirdi va Javaga o'xshash kompilyatorlik tillardan kelgan dasturchilarga visual qulaylik berdi ya'ni syntactic sugar.

Yagona modul tizimi

Har qanday dasturiy ta'minotda dastur kodining yaxshi strukturaviy qismlarga ajratilgani, ham mantiqiy ham jismoniy, bu eng muhim masalalardan biridir. Bunga esa modullar orqali erishiladi. Afsuski, ES6 modul tizimidan oldingi modullash tizimlarida bir qator kamchiliklar mavjud edi, misol uchun server va client uchun universal modul tizimining yo'qligi. Dastlabki modul tizimlaridan farqli o'laroq, yangi ECMAScript Modules (ESM) tizimi statik bog'liqliklardan foydalanish uchun JS sintaksisini yaxshiladi, bu esa 4 ta muhim afzalliklarni berdi:

  • Dastur kodining statik tahlili, o'lik kodni yo'q qilish (dead-code elimination) va keraksiz kodlarni topish (tree-shaking) kabi bir qancha zamonaviy dasturlash vositalarini ishini ancha samaraliroq qilishga imkon yaratdi.
  • Server va client uchun modul tizimini birlashtirdi, bu esa platformaga qarab turli xil modul tizimlarini talab qilish muammosini chiroyli hal etdi. (e.g. CommonJS va AMD)
  • butun dastur bo'ylab kodni qayta-qayta ishlata olishlik imkoniyatini yaxshiladi ya'ni more elegant code sharing.
  • Kompilyatorlarning kodni tahlil qilish usulini optimallashtirdi.

Yashasin export/import yo'qolsin require/define! (bu albatta xazil edi)

Arrow funksiyalar

Bu yangi standartdan oldin, JSda funksiyalarni yaratish uchun function kalitso'zi ishlatilardi, endi esa funksiyalarni => maxsus arrow sintaksisi yordamida ekspressivroq tarzda e'lon qila olamiz. Arrow funksiyalar Pythondagi lambda funksiyalar kabidir va an'anaviy funksiyalardan bir qancha farqlari bor. Xususan, arrow funksiyalar an'anaviy funksiyalardagi this, arguments yoki super kabi mexanizmlarga ega emas . Bundan tashqari, call, apply va bind kabi scopelarni o'zgartira olishda ishlatiladigan vositalar bilan ishlatila olinmaydi.

// ES6 dan oldin 
function add(num1, num2) {
 return num1 + num2;
}

// ES6 dan keyin 
const addImplicit = (num1, num2) => num1 + num2;
Enter fullscreen mode Exit fullscreen mode

Arrow funksiyalaridan foydalanishning eng katta qulayligi sifatida setTimeout() va EventTarget.addEventListener() kabi metodlar bilan oson ishlatilishini aytish mumkin, chunki ularda odatda funksiyaning tegishli scopeda bajarilishini taΚΌminlash uchun closure mexanizmini tadbiq qilinishi yoki bind va apply kabi metodlarni ishlatish talab etiladi.

Destrukturalash sintaksisi

Obyektni destrukturalash obyektning propertiylarini qulay tarzda ajratib olishga va ularni o'zgaruvchilarga osonroq o'zlashtirishga imkon yaratadi. Bu esa dastur kodidagi tartibsizliklarni (code clutter) kamaytirishda samarali rol o'ynab kodni yanada ixcham va o'qishli ko'rinishga keltiradi.
Ko'rib o'zingiz baho bering:

const state = {
 name: "Ahmad",
 age: 25,
 address: {
   zipCode: 7711,
   city: "Tashkent"
 }
}

const { name, address: { zipCode } } = state; // cool!
// solishtirish uchun
const zipCode = state.address.zipCode;
const name = state.address.zipCode;
Enter fullscreen mode Exit fullscreen mode

Meta programming

Proxy obyekti sizga dasturni ishlash jarayonida (runtime) meta levelda muayyan operatsiyalarni intersept qila olish va o'ziga qulay shaklga keltira olish imkoniyatlarini taqdim etadi.

intersept qilish - dasturning biron operatsiyasini bajarilish jarayoni orasiga suqulib kirib unga ta'sir o'tkazish, zimdan kuzatish yoki o'zgartira olishlik. (dasturni ishlash jarayoni bu RAMda aktiv ishchi holatda bo'lishlik degani)
meta level - ya'ni runtime vaqtida dasturlash tilining fundamental mexamizmlari ishlashiga aralasha olish yoki o'zgartira olish

Proxylar muayyan turdagi muammolarni hal qilishda juda foydali mexanizm hisoblanadi. Cross cutting aspects bunga yaqqol misol bo'la oladi. Real misol sifatida esa Vue3 ning reaktiv tizimini keltirish mumkin, ular Proxylardan juda samarali foydalanishgan va oldingi versiyadagi hacky yechimni (Object.defineProperties()) Proxylar bilan almashtirishgan. Bu haqida boshqa maqolalarimizda batafsil to'xtalib o'tamiz.

Iterator va generatorlar

ES6 dagi menga eng yoqqan imkoniyatlardan biri

Bular tilning eng kam tilga olinadigan biroq eng ko'p ishlatiladigan imkoniyatlarini asosida yotuvchi mexanizmlardir (Promise, async/await, etc). JSchilar uchun katta imkoniyatlarni ochib beradi. Bular alohida e'tiborga loyiq mazvular bo'lgani uchun ular haqida ham alohida post yozish istagi bor. Hozircha esa quyidagi code-snippet lar bilan cheklanamiz:

// DOM traversal 
const parent = document.createElement("div");
parent.innerHTML = `
  <div id="subTree">  
    <form>    
      <input type="text"/>  
    </form>  
    <p>Paragraph</p>
    <span>Span</span>
  </div>
`;
const subTree = parent;

// recursive yechim
const traverseDOMRecursive = function (elem, cb) {
  cb(elem);
  elem = elem.firstElementChild;
  while (elem) {
    traverseDOMRecursive(elem, cb);
    elem = elem.nextElementSibling;
  }
};
function callback(element) {
  console.assert(element !== null, element.nodeName);
}
traverseDOMRecursive(subTree, callback);

// generatorlar bilan
const traverseDOMGenerator = function* (elem) {
  yield elem;
  elem = elem.firstElementChild;
  while (elem) {
    yield* traverseDOMGenerator(elem);
    elem = elem.nextElementSibling;
  }
};
// for loop ni ichida ishlatilishiga e'tibor bering
for (let element of traverseDOMGenerator(subTree)) {
  console.log("element", element.nodeName);
}
Enter fullscreen mode Exit fullscreen mode

Endi esa iteratorlarga misol:

class Range {
  constructor(...args) {
    this.start = args.length <= 1 ? 0 : args[0];
    this.end = args.length <= 1 ? args[0] || 0 : args[1];
    this.step = args.length <= 2 ? 1 : args[2];
  }
  [Symbol.iterator]() {
    return this;
  }
  next() {
    if (this.end > this.start) {
      const result = { done: false, value: this.start };
      this.start = this.start + this.step;
      return result;
    } else return { done: true, value: undefined };
  }
}

function range(...args) {
  return new Range(...args);
}

// ajoyib emasmi!
console.log([...range(4)]);
console.log([...range(2, 5)]);
console.log([...range(1, 10, 3)]);
Enter fullscreen mode Exit fullscreen mode

Block scoped o'zgaruvchilar

ES6 tilga yangi o'zgaruvchilarni olib kirdi va ular var ni o'rnini deyarli to'liq egalladi. ES6 gacha, JSda faqatgina funksional va global scopelar bor edi, let va const qo'shilishi tufayli JSda endi block scope ham mavjud. var bilan e'lon qilingan o'zgaruvchilarda locality mexanizmi yo'q edi shuning uchun odatda global scope da e'lon qilingan boshqa o'zgaruvchilar bilan to'qnashuv bo'lishini oldini olish qiyin edi. Block scope esa bu muammoni hal qildi.

locality - biron o'zgaruvchining dastur kodining faqat o'ziga tegishli qismidagina {} mavjud bo'la olishi.

let x = 5;

function blockExample() {
 let x = 2 // bu funksional scope
 if(x >= 3) {
   let x = 10; // bu block scope
   console.log(x, "if blokining ichida");
 } else {
   let x = 1;
   console.log(x, "else blokining ichida");
 }
 console.log(x, "funksiyani ichidagi");
}

blockExample();
console.log(x, "global x");
Enter fullscreen mode Exit fullscreen mode

const o'z nomi bilan constanta ya'ni o'zgarmas qiymatni bildiradi va u bilan e'lon qilingan o'zgaruvchilarga yangi qiymat berishga urinilsa dastur xatolik qaytaradi.

Template literal

Stringlar bilan ishlash imkoniyatlarini yanada kengaytirdi. Qulay interpolyatsiya ${} sintaksini olib kirdi.

let name = "Ahmad";
const HOLIDAY = "Iyd al-Fitr"; 
// ES6 dan oldin: 
console.log(name + "ning sevimli bayrami bu " + HOLIDAY);
// ES6 dan keyin:
console.log(`${name}ning sevimli bayrami bu ${HOLIDAY}`);
// yoki
const multiLineString = `Cross-cutting concerns are parts 
of a program that rely on or must affect many other 
parts of the system`
Enter fullscreen mode Exit fullscreen mode

Va hokazo!

Yana bir eng muhim yangilik bu: JS ni reliz sikli (tilga yangi imkoniyatlarni davomiy tarzda qo'shib borish davri) yillik ko'rinishga o'tkazildi.

Biroz TC39 haqida

Endi TC39 haqida bir-ikki luqma gap aytamiz. Bu ishchi guruh yetakchi web kompaniyalar a'zolaridan tashkil topgan bo'lib asosiy maqsadi ECMAScriptni rivojlantirib borishdan iborat, bu esa o'z navbatida JSni standartlashtirib borish degani. Bundan tashqari TC39 JSchilar keng ommasiga tilga o'zlarining takliflarini (proposal) berish imkoniyatini bajaruvchi platforma sifatida ham faoliyat yuritadi. Bu takliflar ochiq shaklda butun dunyodagi webchilar ommasiga qo'yiladi va muayyan vaqt davomida belgilangan struktura bo'yicha bir nechta bosqichlarda muhokama qilinadi. Quyida bu haqida biroz to'xtalamiz.

TC39 bosqichlari

  • Stage 0 (strawman): Bu norasmiy bosqich bo'lib, taklif har qanday erkin shaklda bo'lishi mumkin, demak hamma ishtirok eta oladi. Taklifingizni kirgazish uchun esa TC39ning a'zosi bo'lishingiz yoki ECMA Internationalga registratsiya qilishingiz talab etiladi. Registratsiyadan so'ng taklifingizni esdiscuss mailing listi orqali bildirishingiz yoki boshqa takliflarni kuzatib borishingiz mumkin.

  • Stage 1 (proposal): Strawman dan so'ng, biron TC39 a'zosi sizning taklifingiz keyingi bosqichga o'tish uchun qo'llab-quvvatlashi kerak. Bu a'zo berilgan taklif nima uchun foydali ekanligini tushuntirishi va u amalga oshirilganda qanday ishlashi va ko'rinishini tasvirlashi kerak πŸ₯.

  • Stage 2 (draft): Bu bosqichda taklifning to'liq spesifikatsiyasi ishlab chiqiladi va eksperimental hisoblanadi (do it at your own risk ☒️ ). Agar taklif bu bosqichga yetib kela olsa, odatda TC39 bu taklifni qachondir JSni spesifikatsiyasiga kiritilishini kutadi.

  • Stage 3 (candidate): Bu bosqichda berilgan taklif to'liq deb hisoblanadi va imzolanadi. Bu bosqichdan keyin taklifga o'zgartirishlar kiritish juda ham kam bo'lib, faqatgina juda kiritik muammolari topilsagina va ko'p muddatli foydalanishdan so'ngina amalga oshiriladi. Ushbu bosqichda taklifni qo'rqmasdan ishlatsangiz bo'ladi chunki ma'lum muddatdan so'ng, taklif xavfsiz tarzda so'nggi bosqichga o'tkaziladi.

  • Stage 4 (finished): Bu yakuniy bosqich hisoblanadi. Agar taklif bu bosqichgacha yetib kelsa uni endi bemalol formal tarzda ECMAScript standartining spesifikatsiyasiga qo'shildi desa bo'ladi 🏁.

Bunday sog'lom va dinamik usulda tilga yangi imkoniyatlarni kiritib borish juda ham muhim jarayon hisoblanadi. Buning natijasida JS bugungi dunyoning tez o'zgarib boruvchi va murakkab talablariga labbay deb javob bera oladi.
Quyida ushbu taklif (proposal) lardan ba'zilarini keltirib o'tamiz.

  • Private class fieldlari va nihoyat classlarda access modifierlarni (private,static) qo'llash imkonini beruvchi sintaksis.
  • Observablelar streamlarga asoslangan reaktiv dasturlash paradigmasini olib kiradi JSga. Shaxsan menga eng yoqqan takliflardan biri. Bu haqida ham alohida maqola yozish niyat bor. RxJS (Angular) bilan ishlab ko'rganlar bo'lsa buni nimaligini juda yaxshi tushunishadi, endi bu library emas balki native πŸš€ !!!
  • Pipeline operatori UNIXdagi pipe utilitasiga o'xshash asosan funksional tillarga tegishli bo'lgan mexanizmni JS fuksiyalarida ishlatish imkonini beradi.
  • Yangi bind operatori Function.prototype.bind ni yanada elegant tarzda ishlatish imkonini beruvchi yangi sintaksis

Ushbu maqola Internetdan olingan ma'lumotlar yordamida tayyorlandi. Har qanday taklif va mulozalar bosh ustiga, ularni pastdagi sharhlar bo'limida qoldirishingiz mumkin. Maqsadimiz o'zbek tilida IT bilan bo'gliq sifatli contentni ko'paytirish va ularni hammaga qulay uslubda tarqatishdir. Bunda eng katta muammolarimizdan biri bu sohaga oid inglizcha atamalarni qanday qilib tushinarli tarzda, o'z ma'nosidan chiqib ketmagan holda qisqa va lo'nda shaklda yetkazishdir. Chunki to'g'ridan to'g'ri (direct) tarjima ko'p hollarda haddan tashqari uzun, tushunarsiz va o'zining dastlabki ma'nosidan chiqib ketgan shaklga kelib qolishidir. Shuning uchun sarbast (erkin) uslubni (postimizda boshida ham bu haqida biroz to'xtalgandik) sinab ko'rishga qaror qildik. Haligi aytishgandek: Best of both worlds :) !

Top comments (0)